crg: support VGA pixel clock reprogramming
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Thu, 28 Mar 2013 18:07:17 +0000 (19:07 +0100)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Thu, 28 Mar 2013 18:07:17 +0000 (19:07 +0100)
milkymist/m1crg/__init__.py
software/include/hw/flags.h
top.py
verilog/m1crg/m1crg.v

index 0d20fd8f9f17d6f7ac9b06f646cb8b1be9fdf3ee..6938e98df2ef4d8c42c61f38de4a86103a411486 100644 (file)
@@ -3,8 +3,9 @@ from fractions import Fraction
 from migen.fhdl.structure import *
 from migen.fhdl.specials import Instance
 from migen.fhdl.module import Module
+from migen.bank.description import *
 
-class M1CRG(Module):
+class M1CRG(Module, AutoReg):
        def __init__(self, pads, outfreq1x):
                self.clock_domains.cd_sys = ClockDomain()
                self.clock_domains.cd_sys2x_270 = ClockDomain()
@@ -17,12 +18,22 @@ class M1CRG(Module):
                self.clk4x_wr_strb = Signal()
                self.clk4x_rd_strb = Signal()
 
+               self._r_cmd_data = RegisterField(10)
+               self._r_send_cmd_data = RegisterRaw()
+               self._r_send_go = RegisterRaw()
+               self._r_status = RegisterField(3, READ_ONLY, WRITE_ONLY)
+
                ###
                
                infreq = 50*1000000
                ratio = Fraction(outfreq1x)/Fraction(infreq)
                in_period = float(Fraction(1000000000)/Fraction(infreq))
 
+               vga_progdata = Signal()
+               vga_progen = Signal()
+               vga_progdone = Signal()
+               vga_locked = Signal()
+
                self.specials += Instance("m1crg",
                        Instance.Parameter("in_period", in_period),
                        Instance.Parameter("f_mult", ratio.numerator),
@@ -48,4 +59,40 @@ class M1CRG(Module):
                        Instance.Output("ddr_clk_pad_p", pads.ddr_clk_p),
                        Instance.Output("ddr_clk_pad_n", pads.ddr_clk_n),
                        Instance.Output("eth_phy_clk_pad", pads.eth_phy_clk),
-                       Instance.Output("vga_clk_pad", pads.vga_clk))
+                       Instance.Output("vga_clk_pad", pads.vga_clk),
+
+                       Instance.Input("vga_progclk", ClockSignal()),
+                       Instance.Input("vga_progdata", vga_progdata),
+                       Instance.Input("vga_progen", vga_progen),
+                       Instance.Output("vga_progdone", vga_progdone),
+                       Instance.Output("vga_locked", vga_locked))
+
+               remaining_bits = Signal(max=11)
+               transmitting = Signal()
+               self.comb += transmitting.eq(remaining_bits != 0)
+               sr = Signal(10)
+               self.sync += [
+                       If(self._r_send_cmd_data.re,
+                               remaining_bits.eq(10),
+                               sr.eq(self._r_cmd_data.field.r)
+                       ).Elif(transmitting,
+                               remaining_bits.eq(remaining_bits - 1),
+                               sr.eq(sr[1:])
+                       )
+               ]
+               self.comb += [
+                       vga_progdata.eq(transmitting & sr[0]),
+                       vga_progen.eq(transmitting | self._r_send_go.re)
+               ]
+
+               # enforce gap between commands
+               busy_counter = Signal(max=14)
+               busy = Signal()
+               self.comb += busy.eq(busy_counter != 0)
+               self.sync += If(self._r_send_cmd_data.re,
+                               busy_counter.eq(13)
+                       ).Elif(busy,
+                               busy_counter.eq(busy_counter - 1)
+                       )
+
+               self.comb += self._r_status.field.w.eq(Cat(busy, vga_progdone, vga_locked))
index 64f6a7edb792c9cf83383aeb0d186a83da90c656..759246a69907ea7466064e5e53082a927adbbc97 100644 (file)
@@ -18,4 +18,8 @@
 #define MINIMAC_EV_RX1 0x2
 #define MINIMAC_EV_TX  0x4
 
+#define CLKGEN_STATUS_BUSY             0x1
+#define CLKGEN_STATUS_PROGDONE 0x2
+#define CLKGEN_STATUS_LOCKED   0x4
+
 #endif /* __HW_FLAGS_H */
diff --git a/top.py b/top.py
index 96d1787b66a577c795228d88d3d44468e52da56c..e5b111783dc58d52a2bda60758d51e004ac55cd1 100644 (file)
--- a/top.py
+++ b/top.py
@@ -65,17 +65,18 @@ class M1ClockPads:
 class SoC(Module):
        csr_base = 0xe0000000
        csr_map = {
-               "uart":                                 0,
-               "dfii":                                 1,
-               "identifier":                   2,
-               "timer0":                               3,
-               "minimac":                              4,
-               "fb":                                   5,
-               "asmiprobe":                    6,
-               "dvisampler0":                  7,
-               "dvisampler0_edid_mem": 8,
-               "dvisampler1":                  9,
-               "dvisampler1_edid_mem": 10,
+               "crg":                                  0,
+               "uart":                                 1,
+               "dfii":                                 2,
+               "identifier":                   3,
+               "timer0":                               4,
+               "minimac":                              5,
+               "fb":                                   6,
+               "asmiprobe":                    7,
+               "dvisampler0":                  8,
+               "dvisampler0_edid_mem": 9,
+               "dvisampler1":                  10,
+               "dvisampler1_edid_mem": 11,
        }
 
        interrupt_map = {
@@ -134,6 +135,7 @@ class SoC(Module):
                #
                # CSR
                #
+               self.submodules.crg = m1crg.M1CRG(M1ClockPads(platform), clk_freq)
                self.submodules.uart = uart.UART(platform.request("serial"), clk_freq, baud=115200)
                self.submodules.identifier = identifier.Identifier(0x4D31, version, int(clk_freq))
                self.submodules.timer0 = timer.Timer()
@@ -151,11 +153,10 @@ class SoC(Module):
                #
                for k, v in sorted(self.interrupt_map.items(), key=itemgetter(1)):
                        self.comb += self.cpu.interrupt[v].eq(getattr(self, k).ev.irq)
-               
+
                #
                # Clocking
                #
-               self.submodules.crg = m1crg.M1CRG(M1ClockPads(platform), clk_freq)
                self.comb += [
                        self.ddrphy.clk4x_wr_strb.eq(self.crg.clk4x_wr_strb),
                        self.ddrphy.clk4x_rd_strb.eq(self.crg.clk4x_rd_strb)
index d5582d405129e2a2e593504a7c291cd69301b90e..bf91d2be919d1c2e4ff9b943752c669883b6734a 100644 (file)
@@ -33,7 +33,14 @@ module m1crg #(
        
        /* VGA clock */
        output vga_clk,         /* < buffered, to internal clock network */
-       output vga_clk_pad      /* < forwarded through ODDR2, to I/O */
+       output vga_clk_pad,     /* < forwarded through ODDR2, to I/O */
+
+       /* VGA clock control */
+       input vga_progclk,
+       input vga_progdata,
+       input vga_progen,
+       output vga_progdone,
+       output vga_locked
 );
 
 /*
@@ -257,7 +264,6 @@ assign eth_tx_clk = eth_tx_clk_pad;
  * VGA clock
  */
 
-// TODO: hook up the reprogramming interface
 DCM_CLKGEN #(
        .CLKFXDV_DIVIDE(2),
        .CLKFX_DIVIDE(4),
@@ -270,15 +276,15 @@ DCM_CLKGEN #(
        .CLKFX(vga_clk),
        .CLKFX180(),
        .CLKFXDV(),
-       .LOCKED(),
-       .PROGDONE(),
        .STATUS(),
        .CLKIN(pllout4),
        .FREEZEDCM(1'b0),
-       .PROGCLK(1'b0),
-       .PROGDATA(),
-       .PROGEN(1'b0),
-       .RST(1'b0)
+       .PROGCLK(vga_progclk),
+       .PROGDATA(vga_progdata),
+       .PROGEN(vga_progen),
+       .PROGDONE(vga_progdone),
+       .LOCKED(vga_locked),
+       .RST(~pll_lckd)
 );
 
 ODDR2 #(