From 7496ba636043594b51a467440a184a4f6ecf6245 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 21 Nov 2013 00:33:22 +0100 Subject: [PATCH] framebuffer: fix resynchronization after resolution change --- misoclib/framebuffer/__init__.py | 44 ++++++++------- misoclib/framebuffer/format.py | 92 +++++++++++++++++++++---------- software/videomixer/Makefile | 4 +- software/videomixer/ci.c | 4 +- software/videomixer/dvisamplerX.c | 4 +- software/videomixer/processor.c | 7 +-- 6 files changed, 94 insertions(+), 61 deletions(-) diff --git a/misoclib/framebuffer/__init__.py b/misoclib/framebuffer/__init__.py index 7033ed0d..7b8015f1 100644 --- a/misoclib/framebuffer/__init__.py +++ b/misoclib/framebuffer/__init__.py @@ -1,8 +1,9 @@ from migen.fhdl.std import * from migen.flow.actor import * from migen.flow.network import * +from migen.flow import plumbing from migen.bank.description import CSRStorage, AutoCSR -from migen.actorlib import dma_lasmi, structuring, sim, spi +from migen.actorlib import dma_lasmi, structuring, sim, misc from misoclib.framebuffer.format import bpp, pixel_layout, FrameInitiator, VTG from misoclib.framebuffer.phy import Driver @@ -11,26 +12,25 @@ class Framebuffer(Module, AutoCSR): def __init__(self, pads_vga, pads_dvi, lasmim, simulation=False): pack_factor = lasmim.dw//bpp - self._enable = CSRStorage() - self.fi = FrameInitiator(pack_factor) - self.dma = spi.DMAReadController(dma_lasmi.Reader(lasmim), spi.MODE_EXTERNAL, length_reset=640*480*4) - self.driver = Driver(pack_factor, pads_vga, pads_dvi) + g = DataFlowGraph() + + self.fi = FrameInitiator(lasmim.aw, pack_factor) + + intseq = misc.IntSequence(lasmim.aw, lasmim.aw) + dma_out = AbstractActor(plumbing.Buffer) + g.add_connection(self.fi, intseq, source_subr=self.fi.dma_subr()) + g.add_pipeline(intseq, AbstractActor(plumbing.Buffer), dma_lasmi.Reader(lasmim), dma_out) cast = structuring.Cast(lasmim.dw, pixel_layout(pack_factor), reverse_to=True) vtg = VTG(pack_factor) + self.driver = Driver(pack_factor, pads_vga, pads_dvi) - g = DataFlowGraph() - g.add_connection(self.fi, vtg, sink_ep="timing") - g.add_connection(self.dma, cast) + g.add_connection(self.fi, vtg, source_subr=self.fi.timing_subr, sink_ep="timing") + g.add_connection(dma_out, cast) g.add_connection(cast, vtg, sink_ep="pixels") g.add_connection(vtg, self.driver) self.submodules += CompositeActor(g) - self.comb += [ - self.fi.trigger.eq(self._enable.storage), - self.dma.generator.trigger.eq(self._enable.storage), - ] - class Blender(PipelinedActor, AutoCSR): def __init__(self, nimages, pack_factor, latency): epixel_layout = pixel_layout(pack_factor) @@ -79,26 +79,28 @@ class Blender(PipelinedActor, AutoCSR): class MixFramebuffer(Module, AutoCSR): def __init__(self, pads_vga, pads_dvi, *lasmims, blender_latency=5): + assert(all(lasmim.aw == lasmims[0].aw and lasmim.dw == lasmims[0].dw + for lasmim in lasmims)) pack_factor = lasmims[0].dw//bpp - self._enable = CSRStorage() - self.fi = FrameInitiator(pack_factor) + self.fi = FrameInitiator(lasmims[0].aw, pack_factor, len(lasmims)) self.blender = Blender(len(lasmims), pack_factor, blender_latency) self.driver = Driver(pack_factor, pads_vga, pads_dvi) - self.comb += self.fi.trigger.eq(self._enable.storage) g = DataFlowGraph() epixel_layout = pixel_layout(pack_factor) for n, lasmim in enumerate(lasmims): - dma = spi.DMAReadController(dma_lasmi.Reader(lasmim), spi.MODE_EXTERNAL, length_reset=640*480*4) + intseq = misc.IntSequence(lasmim.aw, lasmim.aw) + dma_out = AbstractActor(plumbing.Buffer) + g.add_connection(self.fi, intseq, source_subr=self.fi.dma_subr(n)) + g.add_pipeline(intseq, AbstractActor(plumbing.Buffer), dma_lasmi.Reader(lasmim), dma_out) + cast = structuring.Cast(lasmim.dw, epixel_layout, reverse_to=True) - g.add_connection(dma, cast) + g.add_connection(dma_out, cast) g.add_connection(cast, self.blender, sink_subr=["i"+str(n)]) - self.comb += dma.generator.trigger.eq(self._enable.storage) - setattr(self, "dma"+str(n), dma) vtg = VTG(pack_factor) - g.add_connection(self.fi, vtg, sink_ep="timing") + g.add_connection(self.fi, vtg, source_subr=self.fi.timing_subr, sink_ep="timing") g.add_connection(self.blender, vtg, sink_ep="pixels") g.add_connection(vtg, self.driver) self.submodules += CompositeActor(g) diff --git a/misoclib/framebuffer/format.py b/misoclib/framebuffer/format.py index 25f3588d..5242d2d9 100644 --- a/misoclib/framebuffer/format.py +++ b/misoclib/framebuffer/format.py @@ -1,6 +1,8 @@ from migen.fhdl.std import * from migen.flow.actor import * from migen.bank.description import CSRStorage +from migen.genlib.record import Record +from migen.genlib.fsm import FSM, NextState from migen.actorlib import spi _hbits = 12 @@ -30,9 +32,10 @@ def phy_layout(pack_factor): return r class FrameInitiator(spi.SingleGenerator): - def __init__(self, pack_factor): + def __init__(self, bus_aw, pack_factor, ndmas=1): h_alignment_bits = log2_int(pack_factor) hbits_dyn = _hbits - h_alignment_bits + bus_alignment_bits = h_alignment_bits + log2_int(bpp//8) layout = [ ("hres", hbits_dyn, 640, h_alignment_bits), ("hsync_start", hbits_dyn, 656, h_alignment_bits), @@ -42,31 +45,43 @@ class FrameInitiator(spi.SingleGenerator): ("vres", _vbits, 480), ("vsync_start", _vbits, 492), ("vsync_end", _vbits, 494), - ("vscan", _vbits, 525) + ("vscan", _vbits, 525), + + ("length", bus_aw + bus_alignment_bits, 640*480*bpp//8, bus_alignment_bits) ] - spi.SingleGenerator.__init__(self, layout, spi.MODE_EXTERNAL) + layout += [("base"+str(i), bus_aw + bus_alignment_bits, 0, bus_alignment_bits) + for i in range(ndmas)] + spi.SingleGenerator.__init__(self, layout, spi.MODE_CONTINUOUS) + + timing_subr = ["hres", "hsync_start", "hsync_end", "hscan", + "vres", "vsync_start", "vsync_end", "vscan"] + + def dma_subr(self, i=0): + return ["length", "base"+str(i)] class VTG(Module): def __init__(self, pack_factor): hbits_dyn = _hbits - log2_int(pack_factor) - self.timing = Sink([ - ("hres", hbits_dyn), - ("hsync_start", hbits_dyn), - ("hsync_end", hbits_dyn), - ("hscan", hbits_dyn), - ("vres", _vbits), - ("vsync_start", _vbits), - ("vsync_end", _vbits), - ("vscan", _vbits)]) + timing_layout = [ + ("hres", hbits_dyn), + ("hsync_start", hbits_dyn), + ("hsync_end", hbits_dyn), + ("hscan", hbits_dyn), + ("vres", _vbits), + ("vsync_start", _vbits), + ("vsync_end", _vbits), + ("vscan", _vbits)] + self.timing = Sink(timing_layout) self.pixels = Sink(pixel_layout(pack_factor)) self.phy = Source(phy_layout(pack_factor)) self.busy = Signal() + ### + hactive = Signal() vactive = Signal() active = Signal() - generate_en = Signal() hcounter = Signal(hbits_dyn) vcounter = Signal(_vbits) @@ -78,35 +93,52 @@ class VTG(Module): for p in ["p"+str(i) for i in range(pack_factor)] for c in ["r", "g", "b"]], self.phy.payload.de.eq(1) ), - - generate_en.eq(self.timing.stb & (~active | self.pixels.stb)), - self.pixels.ack.eq(self.phy.ack & active), - self.phy.stb.eq(generate_en), - self.busy.eq(generate_en) + self.pixels.ack.eq(self.phy.ack & active) ] - tp = self.timing.payload + + load_timing = Signal() + tr = Record(timing_layout) + self.sync += If(load_timing, tr.eq(self.timing.payload)) + + generate_en = Signal() + generate_frame_done = Signal() self.sync += [ - self.timing.ack.eq(0), - If(generate_en & self.phy.ack, + generate_frame_done.eq(0), + If(generate_en, hcounter.eq(hcounter + 1), If(hcounter == 0, hactive.eq(1)), - If(hcounter == tp.hres, hactive.eq(0)), - If(hcounter == tp.hsync_start, self.phy.payload.hsync.eq(1)), - If(hcounter == tp.hsync_end, self.phy.payload.hsync.eq(0)), - If(hcounter == tp.hscan, + If(hcounter == tr.hres, hactive.eq(0)), + If(hcounter == tr.hsync_start, self.phy.payload.hsync.eq(1)), + If(hcounter == tr.hsync_end, self.phy.payload.hsync.eq(0)), + If(hcounter == tr.hscan, hcounter.eq(0), - If(vcounter == tp.vscan, + If(vcounter == tr.vscan, vcounter.eq(0), - self.timing.ack.eq(1) + generate_frame_done.eq(1) ).Else( vcounter.eq(vcounter + 1) ) ), If(vcounter == 0, vactive.eq(1)), - If(vcounter == tp.vres, vactive.eq(0)), - If(vcounter == tp.vsync_start, self.phy.payload.vsync.eq(1)), - If(vcounter == tp.vsync_end, self.phy.payload.vsync.eq(0)) + If(vcounter == tr.vres, vactive.eq(0)), + If(vcounter == tr.vsync_start, self.phy.payload.vsync.eq(1)), + If(vcounter == tr.vsync_end, self.phy.payload.vsync.eq(0)) ) ] + + self.submodules.fsm = FSM() + self.fsm.act("GET_TIMING", + self.timing.ack.eq(1), + load_timing.eq(1), + If(self.timing.stb, NextState("GENERATE")) + ) + self.fsm.act("GENERATE", + self.busy.eq(1), + If(~active | self.pixels.stb, + self.phy.stb.eq(1), + If(self.phy.ack, generate_en.eq(1)) + ), + If(generate_frame_done, NextState("GET_TIMING")) + ) diff --git a/software/videomixer/Makefile b/software/videomixer/Makefile index 6111c9da..8920d60f 100644 --- a/software/videomixer/Makefile +++ b/software/videomixer/Makefile @@ -39,12 +39,12 @@ main.o: main.c define gen0 @echo " GEN " $@ -@sed -e "s/dvisamplerX/dvisampler0/g;s/DVISAMPLERX/DVISAMPLER0/g;s/fb_dmaX/fb_dma0/g" $< > $@ +@sed -e "s/dvisamplerX/dvisampler0/g;s/DVISAMPLERX/DVISAMPLER0/g;s/fb_fi_baseX/fb_fi_base0/g" $< > $@ endef define gen1 @echo " GEN " $@ -@sed -e "s/dvisamplerX/dvisampler1/g;s/DVISAMPLERX/DVISAMPLER1/g;s/fb_dmaX/fb_dma1/g" $< > $@ +@sed -e "s/dvisamplerX/dvisampler1/g;s/DVISAMPLERX/DVISAMPLER1/g;s/fb_fi_baseX/fb_fi_base1/g" $< > $@ endef dvisampler0.c: dvisamplerX.c diff --git a/software/videomixer/ci.c b/software/videomixer/ci.c index 06fdf98b..f6f1110a 100644 --- a/software/videomixer/ci.c +++ b/software/videomixer/ci.c @@ -62,11 +62,11 @@ void ci_service(void) printf("DVI sampler debug is OFF\n"); break; case 'F': - fb_enable_write(1); + fb_fi_enable_write(1); printf("framebuffer is ON\n"); break; case 'f': - fb_enable_write(0); + fb_fi_enable_write(0); printf("framebuffer is OFF\n"); break; case 'm': diff --git a/software/videomixer/dvisamplerX.c b/software/videomixer/dvisamplerX.c index eb0521bc..088519c7 100644 --- a/software/videomixer/dvisamplerX.c +++ b/software/videomixer/dvisamplerX.c @@ -76,7 +76,7 @@ void dvisamplerX_isr(void) } if(fb_index != -1) - fb_dmaX_base_write((unsigned int)dvisamplerX_framebuffers[fb_index]); + fb_fi_baseX_write((unsigned int)dvisamplerX_framebuffers[fb_index]); } static int dvisamplerX_connected; @@ -105,7 +105,7 @@ void dvisamplerX_init_video(int hres, int vres) mask |= 1 << DVISAMPLERX_INTERRUPT; irq_setmask(mask); - fb_dmaX_base_write((unsigned int)dvisamplerX_framebuffers[3]); + fb_fi_baseX_write((unsigned int)dvisamplerX_framebuffers[3]); } void dvisamplerX_disable(void) diff --git a/software/videomixer/processor.c b/software/videomixer/processor.c index 60e33379..d5580d1c 100644 --- a/software/videomixer/processor.c +++ b/software/videomixer/processor.c @@ -228,8 +228,7 @@ static void fb_set_mode(const struct video_timing *mode) fb_fi_vsync_end_write(mode->v_active + mode->v_sync_offset + mode->v_sync_width); fb_fi_vscan_write(mode->v_active + mode->v_blanking); - fb_dma0_length_write(mode->h_active*mode->v_active*4); - fb_dma1_length_write(mode->h_active*mode->v_active*4); + fb_fi_length_write(mode->h_active*mode->v_active*4); fb_clkgen_write(0x1, clock_d-1); fb_clkgen_write(0x3, clock_m-1); @@ -255,7 +254,7 @@ void processor_start(int mode) { const struct video_timing *m = &video_modes[mode]; - fb_enable_write(0); + fb_fi_enable_write(0); fb_driver_clocking_pll_reset_write(1); dvisampler0_edid_hpd_en_write(0); dvisampler1_edid_hpd_en_write(0); @@ -272,7 +271,7 @@ void processor_start(int mode) dvisampler1_init_video(m->h_active, m->v_active); fb_driver_clocking_pll_reset_write(0); - fb_enable_write(1); + fb_fi_enable_write(1); dvisampler0_edid_hpd_en_write(1); dvisampler1_edid_hpd_en_write(1); } -- 2.30.2