phy/pcs_1000basex: Update from misoc.

This commit is contained in:
Florent Kermarrec 2023-06-13 09:52:20 +02:00
parent e9605ef9d8
commit 7046987ff1
1 changed files with 70 additions and 51 deletions

View File

@ -9,7 +9,8 @@ from math import ceil
from migen import *
from migen.genlib.fsm import *
from migen.genlib.misc import WaitTimer
from migen.genlib.cdc import PulseSynchronizer
from migen.genlib.cdc import PulseSynchronizer, BusSynchronizer
from litex.soc.interconnect import stream
from litex.soc.cores import code_8b10b
@ -176,7 +177,7 @@ class ReceivePath(Module):
load_config_reg_msb = Signal()
self.sync += [
self.seen_config_reg.eq(0),
If(load_config_reg_lsb,
If(load_config_reg_lsb,
config_reg_lsb.eq(self.decoder.d)
),
If(load_config_reg_msb,
@ -284,12 +285,11 @@ class PCS(Module):
self.link_up = Signal()
self.restart = Signal()
# SGMII Speed Adaptation
is_sgmii = Signal()
self.link_partner_adv_ability = Signal(16)
self.lp_abi = BusSynchronizer(16, "eth_rx", "eth_tx")
self.submodules += self.lp_abi
# # #
# endpoint interface
self.comb += [
self.tx.tx_stb.eq(self.sink.valid),
@ -326,12 +326,34 @@ class PCS(Module):
If(checker_tick, checker_ok.eq(0))
]
# Control if tx_config_reg should be empty
tx_config_empty = Signal()
# Detections in SGMII mode
is_sgmii = Signal()
linkdown = Signal()
self.comb += [
is_sgmii.eq(self.lp_abi.o[0]),
# Detect that link is down:
# - 1000BASE-X: linkup can be inferred by non-empty reg
# - SGMII: linkup is indicated with bit 15
linkdown.eq((self.lp_abi.o[0] & ~self.lp_abi.o[15]) | (self.lp_abi.o == 0)),
self.tx.sgmii_speed.eq(Mux(self.lp_abi.o[0],
self.lp_abi.o[10:12], 0b10)),
self.rx.sgmii_speed.eq(Mux(self.lp_abi.i[0],
self.lp_abi.i[10:12], 0b10))
]
autoneg_ack = Signal()
self.comb += self.tx.config_reg.eq(
(is_sgmii) | # SGMII-specific
(~is_sgmii << 5) | # Full-duplex
(autoneg_ack << 14) # ACK
)
self.comb += [
self.tx.config_reg.eq(Mux(tx_config_empty, 0,
(is_sgmii) | # SGMII: SGMII in-use
(~is_sgmii << 5) | # 1000BASE-X: Full-duplex
(Mux(self.lp_abi.o[0], # SGMII: Speed
self.lp_abi.o[10:12], 0) << 10) |
(is_sgmii << 12) | # SGMII: Full-duplex
(autoneg_ack << 14) | # SGMII/1000BASE-X: Acknowledge Bit
(is_sgmii & self.link_up) # SGMII: Link-up
))
]
rx_config_reg_abi = PulseSynchronizer("eth_rx", "eth_tx")
rx_config_reg_ack = PulseSynchronizer("eth_rx", "eth_tx")
@ -341,25 +363,35 @@ class PCS(Module):
more_ack_timer = ClockDomainsRenamer("eth_tx")(
WaitTimer(ceil(more_ack_time*125e6)))
self.submodules += more_ack_timer
fsm_inited = Signal()
config_reg_empty = Signal()
# SGMII: use 1.6ms link_timer
sgmii_ack_timer = ClockDomainsRenamer("eth_tx")(
WaitTimer(ceil(1.6e-3*125e6)))
self.submodules += more_ack_timer, sgmii_ack_timer
fsm = ClockDomainsRenamer("eth_tx")(FSM())
self.submodules += fsm
# AN_ENABLE
fsm.act("AUTONEG_BREAKLINK",
self.tx.config_stb.eq(1),
tx_config_empty.eq(1),
more_ack_timer.wait.eq(1),
If(more_ack_timer.done,
NextState("AUTONEG_WAIT_ABI")
)
)
# ABILITY_DETECT
fsm.act("AUTONEG_WAIT_ABI",
self.tx.config_stb.eq(fsm_inited),
self.tx.config_stb.eq(1),
If(rx_config_reg_abi.o,
NextValue(fsm_inited, 1),
NextState("AUTONEG_WAIT_ACK")
),
If(checker_tick & ~checker_ok,
self.restart.eq(1),
NextState("AUTONEG_WAIT_ABI")
NextState("AUTONEG_BREAKLINK")
)
)
# ACKNOWLEDGE_DETECT
fsm.act("AUTONEG_WAIT_ACK",
self.tx.config_stb.eq(1),
autoneg_ack.eq(1),
@ -368,34 +400,35 @@ class PCS(Module):
),
If(checker_tick & ~checker_ok,
self.restart.eq(1),
NextState("AUTONEG_WAIT_ABI")
NextState("AUTONEG_BREAKLINK")
)
)
# COMPLETE_ACKNOWLEDGE
fsm.act("AUTONEG_SEND_MORE_ACK",
self.tx.config_stb.eq(1),
autoneg_ack.eq(1),
more_ack_timer.wait.eq(1),
If(more_ack_timer.done,
more_ack_timer.wait.eq(~is_sgmii),
sgmii_ack_timer.wait.eq(is_sgmii),
If((is_sgmii & sgmii_ack_timer.done) |
(~is_sgmii & more_ack_timer.done),
NextState("RUNNING")
),
If(checker_tick & ~checker_ok,
self.restart.eq(1),
NextState("AUTONEG_WAIT_ABI")
NextState("AUTONEG_BREAKLINK")
)
)
# LINK_OK
fsm.act("RUNNING",
self.link_up.eq(1),
If((checker_tick & ~checker_ok) | config_reg_empty,
If((checker_tick & ~checker_ok) | linkdown,
self.restart.eq(1),
NextState("AUTONEG_WAIT_ABI")
NextState("AUTONEG_BREAKLINK")
)
)
c_counter = Signal(max=5)
previous_config_reg = Signal(16)
preack_config_reg = Signal(16)
prev_config_reg = Signal(16)
self.sync.eth_rx += [
# Restart consistency counter
If(self.rx.seen_config_reg,
@ -407,34 +440,20 @@ class PCS(Module):
rx_config_reg_abi.i.eq(0),
rx_config_reg_ack.i.eq(0),
If(self.rx.seen_config_reg,
previous_config_reg.eq(self.rx.config_reg),
If((c_counter == 1) &
((previous_config_reg|0x4000) == (self.rx.config_reg|0x4000)) &
((self.rx.config_reg | 1) != 1),
# Ability match
rx_config_reg_abi.i.eq(1),
preack_config_reg.eq(previous_config_reg),
# Record current config_reg for comparison in the next clock cycle
prev_config_reg.eq(self.rx.config_reg),
# Compare consecutive values of config_reg
If((c_counter == 1) & (prev_config_reg&0xbfff == self.rx.config_reg&0xbfff),
# Acknowledgement/Consistency match
If((previous_config_reg[14] & self.rx.config_reg[14]) &
((preack_config_reg|0x4000) == (self.rx.config_reg|0x4000)),
rx_config_reg_ack.i.eq(1)
If(prev_config_reg[14] & self.rx.config_reg[14],
rx_config_reg_ack.i.eq(1),
)
# Ability match
.Else(
rx_config_reg_abi.i.eq(1),
)
),
# Record advertised ability of link partner
self.link_partner_adv_ability.eq(self.rx.config_reg)
self.lp_abi.i.eq(self.rx.config_reg)
)
]
# Speed detection via SGMII
sgmii_speed = Mux(is_sgmii,
self.link_partner_adv_ability[10:12], 0b10)
self.comb += [
is_sgmii.eq(self.link_partner_adv_ability[0]),
self.tx.sgmii_speed.eq(sgmii_speed),
self.rx.sgmii_speed.eq(sgmii_speed)
]
# Detect that config_reg is empty
self.comb += [
config_reg_empty.eq((self.link_partner_adv_ability | 1) == 1)
]