From 8460523f276f54057bb27f54330bcbacbe6f67e4 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 18 Mar 2021 14:43:08 +0100 Subject: [PATCH] cores/video: Add VideoECP5HDMI PHY and move 10to1 Serializer to Generic, share it for Spartan6/ECP5. --- litex/soc/cores/video.py | 42 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/litex/soc/cores/video.py b/litex/soc/cores/video.py index af4cfe54e..088760420 100644 --- a/litex/soc/cores/video.py +++ b/litex/soc/cores/video.py @@ -674,9 +674,9 @@ class VideoDVIPHY(Module): self.specials += SDROutput(i=sink.g[cshift + i], o=pads.g[i], clk=ClockSignal(clock_domain)) self.specials += SDROutput(i=sink.b[cshift + i], o=pads.b[i], clk=ClockSignal(clock_domain)) -# HDMI (Xilinx Spartan6). +# HDMI (Generic). -class VideoS6HDMI10to1Serializer(Module): +class VideoHDMI10to1Serializer(Module): def __init__(self, data_i, data_o, clock_domain): # Clock Domain Crossing. self.submodules.cdc = stream.ClockDomainCrossing([("data", 10)], cd_from=clock_domain, cd_to=clock_domain + "5x") @@ -696,6 +696,8 @@ class VideoS6HDMI10to1Serializer(Module): o = data_o, ) +# HDMI (Xilinx Spartan6). + class VideoS6HDMIPHY(Module): def __init__(self, pads, clock_domain="sys"): self.sink = sink = stream.Endpoint(video_data_layout) @@ -722,7 +724,7 @@ class VideoS6HDMIPHY(Module): # 10:1 Serialization + Differential Signaling. pad_o = Signal() - serializer = VideoS6HDMI10to1Serializer( + serializer = VideoHDMI10to1Serializer( data_i = encoder.out, data_o = pad_o, clock_domain = clock_domain, @@ -813,3 +815,37 @@ class VideoS7HDMIPHY(Module): pad_p = getattr(pads, f"data{c2d[color]}_p") pad_n = getattr(pads, f"data{c2d[color]}_n") self.specials += Instance("OBUFDS", i_I=pad_o, o_O=pad_p, o_OB=pad_n) + + +# HDMI (Lattice ECP5). + +class VideoECP5HDMIPHY(Module): + def __init__(self, pads, clock_domain="sys"): + self.sink = sink = stream.Endpoint(video_data_layout) + + # # # + + # Always ack Sink, no backpressure. + self.comb += sink.ready.eq(1) + + # Clocking + Pseudo Differential Signaling. + self.specials += DDROutput(i1=1, i2=0, o=pads.clk_p, clk=ClockSignal(clock_domain)) + + # Encode/Serialize Datas. + for color in ["r", "g", "b"]: + + # TMDS Encoding. + encoder = ClockDomainsRenamer(clock_domain)(TMDSEncoder()) + setattr(self.submodules, f"{color}_encoder", encoder) + self.comb += encoder.d.eq(getattr(sink, color)) + self.comb += encoder.c.eq(Cat(sink.hsync, sink.vsync) if color == "r" else 0) + self.comb += encoder.de.eq(sink.de) + + # 10:1 Serialization + Pseudo Differential Signaling. + c2d = {"r": 0, "g": 1, "b": 2} + serializer = VideoHDMI10to1Serializer( + data_i = encoder.out, + data_o = getattr(pads, f"data{c2d[color]}_p"), + clock_domain = clock_domain, + ) + setattr(self.submodules, f"{color}_serializer", serializer)