cores/video/VideoHDMIPHY: Rework Fake Differential support and automatically detect when required.
- Detect activation from passed pads: If p and n present -> Activate. - Make code a bit more generic to avoid if/else. - Keep change self contained to VideoHDMIPHY to avoid propagating features to VideoHDMI10to1Serializer. (Less optimal in term of resources since doubling the serializers, but should be negligible and we are fixing a hardware issue here...).
This commit is contained in:
parent
8fd96cab84
commit
7e1d2bdf9b
|
@ -740,7 +740,7 @@ class VideoDVIPHY(VideoGenericPHY): pass
|
||||||
# HDMI (Generic).
|
# HDMI (Generic).
|
||||||
|
|
||||||
class VideoHDMI10to1Serializer(Module):
|
class VideoHDMI10to1Serializer(Module):
|
||||||
def __init__(self, data_i, data_o, clock_domain, data_o_n=Signal(), drive_both=False):
|
def __init__(self, data_i, data_o, clock_domain):
|
||||||
# Clock Domain Crossing.
|
# Clock Domain Crossing.
|
||||||
self.submodules.cdc = stream.ClockDomainCrossing([("data", 10)], cd_from=clock_domain, cd_to=clock_domain + "5x")
|
self.submodules.cdc = stream.ClockDomainCrossing([("data", 10)], cd_from=clock_domain, cd_to=clock_domain + "5x")
|
||||||
self.comb += self.cdc.sink.valid.eq(1)
|
self.comb += self.cdc.sink.valid.eq(1)
|
||||||
|
@ -758,31 +758,35 @@ class VideoHDMI10to1Serializer(Module):
|
||||||
i2 = self.gearbox.source.data[1],
|
i2 = self.gearbox.source.data[1],
|
||||||
o = data_o,
|
o = data_o,
|
||||||
)
|
)
|
||||||
if drive_both:
|
|
||||||
self.specials += DDROutput(
|
|
||||||
clk = ClockSignal(clock_domain + "5x"),
|
|
||||||
i1 = ~self.gearbox.source.data[0],
|
|
||||||
i2 = ~self.gearbox.source.data[1],
|
|
||||||
o = data_o_n,
|
|
||||||
)
|
|
||||||
|
|
||||||
class VideoHDMIPHY(Module):
|
class VideoHDMIPHY(Module):
|
||||||
def __init__(self, pads, clock_domain="sys", pn_swap=[], drive_both=False):
|
def __init__(self, pads, clock_domain="sys", pn_swap=[]):
|
||||||
self.sink = sink = stream.Endpoint(video_data_layout)
|
self.sink = sink = stream.Endpoint(video_data_layout)
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
|
# Determine driven polarities:
|
||||||
|
# - p only for True/Pseudo Differential.
|
||||||
|
# - p and n for Fake Differential.
|
||||||
|
drive_pols = []
|
||||||
|
for pol in ["p", "n"]:
|
||||||
|
if hasattr(pads, f"clk_{pol}"):
|
||||||
|
drive_pols.append(pol)
|
||||||
|
|
||||||
# Always ack Sink, no backpressure.
|
# Always ack Sink, no backpressure.
|
||||||
self.comb += sink.ready.eq(1)
|
self.comb += sink.ready.eq(1)
|
||||||
|
|
||||||
# Clocking + Pseudo Differential Signaling.
|
# Clocking + Pseudo Differential Signaling.
|
||||||
self.specials += DDROutput(i1=1, i2=0, o=pads.clk_p, clk=ClockSignal(clock_domain))
|
for pol in drive_pols:
|
||||||
if drive_both:
|
self.specials += DDROutput(
|
||||||
self.specials += DDROutput(i1=0, i2=1, o=pads.clk_n, clk=ClockSignal(clock_domain))
|
i1 = {"p" : 1, "n" : 0}[pol],
|
||||||
|
i2 = {"p" : 0, "n" : 1}[pol],
|
||||||
data_n = Signal()
|
o = getattr(pads, f"clk_{pol}"),
|
||||||
|
clk = ClockSignal(clock_domain),
|
||||||
|
)
|
||||||
|
|
||||||
# Encode/Serialize Datas.
|
# Encode/Serialize Datas.
|
||||||
|
for pol in drive_pols:
|
||||||
for color in ["r", "g", "b"]:
|
for color in ["r", "g", "b"]:
|
||||||
# TMDS Encoding.
|
# TMDS Encoding.
|
||||||
encoder = ClockDomainsRenamer(clock_domain)(TMDSEncoder())
|
encoder = ClockDomainsRenamer(clock_domain)(TMDSEncoder())
|
||||||
|
@ -793,15 +797,12 @@ class VideoHDMIPHY(Module):
|
||||||
|
|
||||||
# 10:1 Serialization + Pseudo Differential Signaling.
|
# 10:1 Serialization + Pseudo Differential Signaling.
|
||||||
c2d = {"r": 0, "g": 1, "b": 2}
|
c2d = {"r": 0, "g": 1, "b": 2}
|
||||||
data = encoder.out if color not in pn_swap else ~encoder.out
|
data_i = encoder.out if color not in pn_swap else ~encoder.out
|
||||||
if drive_both:
|
data_o = getattr(pads, f"data{c2d[color]}_{pol}")
|
||||||
data_n = getattr(pads, f"data{c2d[color]}_n")
|
|
||||||
serializer = VideoHDMI10to1Serializer(
|
serializer = VideoHDMI10to1Serializer(
|
||||||
data_i = data,
|
data_i = {"p":data_i, "n": ~data_i}[pol],
|
||||||
data_o = getattr(pads, f"data{c2d[color]}_p"),
|
data_o = data_o,
|
||||||
data_o_n = data_n,
|
|
||||||
clock_domain = clock_domain,
|
clock_domain = clock_domain,
|
||||||
drive_both = drive_both,
|
|
||||||
)
|
)
|
||||||
setattr(self.submodules, f"{color}_serializer", serializer)
|
setattr(self.submodules, f"{color}_serializer", serializer)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue