Improve PLL/MMCM clocks configuration
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Tue, 24 Sep 2019 04:57:34 +0000 (14:57 +1000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Mon, 30 Sep 2019 03:57:36 +0000 (13:57 +1000)
We can now pass both the input clock and target clock frequency
via generics. Add support for both 50Mhz and 100Mhz target freqs
for both cases.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
fpga/clk_gen_mcmm.vhd
fpga/clk_gen_plle2.vhd
fpga/toplevel.vhdl
microwatt.core

index 206b02acaca8d2a42cb755db6eb63a8cedf7beee..08db930d7d4554fd6991dda35e937b29d9a91a17 100644 (file)
@@ -6,7 +6,9 @@ use UNISIM.vcomponents.all;
 
 entity clock_generator is
     generic (
-        clk_period_hz  : positive := 12000000);
+        CLK_INPUT_HZ  : positive := 12000000;
+        CLK_OUTPUT_HZ : positive := 50000000
+       );
     port (
         ext_clk        : in  std_logic;
         pll_rst_in     : in  std_logic;
@@ -22,28 +24,66 @@ architecture rtl of clock_generator is
         clkfbout_mult : real range 2.0 to 64.0;
         clkout_divide : real range 1.0 to 128.0;
         divclk_divide : integer range 1 to 106;
+       force_rst     : std_ulogic;
     end record;
 
     function gen_pll_settings (
-        constant freq_hz : positive)
+        constant input_hz : positive;
+       constant output_hz : positive)
         return pll_settings_t is
+
+       constant bad_settings : pll_settings_t :=
+           (clkin_period  => 0.0,
+            clkfbout_mult => 2.0,
+            clkout_divide => 1.0,
+            divclk_divide => 1,
+            force_rst     => '1');
     begin
-        if freq_hz = 100000000 then
-            return (clkin_period  => 10.0,
-                    clkfbout_mult => 16.0,
-                    clkout_divide => 32.0,
-                    divclk_divide => 1);
-        elsif freq_hz = 12000000 then
-            return (clkin_period  => 83.33,
-                    clkfbout_mult => 50.0,
-                    clkout_divide => 12.0,
-                    divclk_divide => 1);
-        else
-            report "Unsupported input frequency" severity failure;
-        end if;
+        case input_hz is
+       when 100000000 =>
+           case output_hz is
+           when 100000000 =>
+               return (clkin_period  => 10.0,
+                       clkfbout_mult => 16.0,
+                       clkout_divide => 16.0,
+                       divclk_divide => 1,
+                       force_rst     => '0');
+           when  50000000 =>
+               return (clkin_period  => 10.0,
+                       clkfbout_mult => 16.0,
+                       clkout_divide => 32.0,
+                       divclk_divide => 1,
+                       force_rst     => '0');
+           when others =>
+               report "Unsupported output frequency" severity failure;
+               return bad_settings;
+           end case;
+       when 12000000 =>
+           case output_hz is
+           when 100000000 =>
+               return (clkin_period  => 83.33,
+                       clkfbout_mult => 50.0,
+                       clkout_divide => 6.0,
+                       divclk_divide => 1,
+                       force_rst     => '0');                  
+           when  50000000 =>
+               return (clkin_period  => 83.33,
+                       clkfbout_mult => 50.0,
+                       clkout_divide => 12.0,
+                       divclk_divide => 1,
+                       force_rst     => '0');
+           when others =>
+               report "Unsupported output frequency" severity failure;
+               return bad_settings;
+           end case;
+       when others =>
+           report "Unsupported input frequency" severity failure;
+           return bad_settings;
+        end case;
     end function gen_pll_settings;
 
-    constant pll_settings : pll_settings_t := gen_pll_settings(clk_period_hz);
+    constant pll_settings : pll_settings_t := gen_pll_settings(clk_input_hz,
+                                                              clk_output_hz);
 begin
     pll : MMCME2_BASE
         generic map (
@@ -71,6 +111,6 @@ begin
             CLKFBIN    => clkfb,
             CLKIN1     => ext_clk,
             PWRDWN     => '0',
-            RST        => pll_rst_in
+           RST      => pll_rst_in or pll_settings.force_rst
             );
 end architecture rtl;
index f82cb53beed019d62aa33527972201855463b434..750840b5ee1a522669bca4ad1df8d5add8d45cdd 100644 (file)
@@ -5,67 +5,89 @@ Library UNISIM;
 use UNISIM.vcomponents.all;
 
 entity clock_generator is
-  generic (
-    clk_period_hz : positive := 100000000);
-  port (
-    ext_clk        : in  std_logic;
-    pll_rst_in   : in  std_logic;
-    pll_clk_out    : out std_logic;
-    pll_locked_out : out std_logic);
+    generic (
+       CLK_INPUT_HZ  : positive := 100000000;
+       CLK_OUTPUT_HZ : positive := 100000000
+       );
+    port (
+       ext_clk        : in  std_logic;
+       pll_rst_in   : in  std_logic;
+       pll_clk_out    : out std_logic;
+       pll_locked_out : out std_logic);
 end entity clock_generator;
 
 architecture rtl of clock_generator is
+    signal clkfb : std_ulogic;
 
-  signal clkfb : std_ulogic;
+    type pll_settings_t is record
+       clkin_period  : real    range 0.000 to 52.631;
+       clkfbout_mult : integer range 2 to 64;
+       clkout_divide : integer range 1 to 128;
+       divclk_divide : integer range 1 to 56;
+       force_rst     : std_ulogic;
+    end record;
 
-  type pll_settings_t is record
-    clkin_period  : real    range 0.000 to 52.631;
-    clkfbout_mult : integer range 2 to 64;
-    clkout_divide : integer range 1 to 128;
-    divclk_divide : integer range 1 to 56;
-  end record;
+    function gen_pll_settings (
+        constant input_hz : positive;
+       constant output_hz : positive)
+       return pll_settings_t is
 
-  function gen_pll_settings (
-    constant freq_hz : positive)
-    return pll_settings_t is
-  begin
-    if freq_hz = 100000000 then
-      return (clkin_period  => 10.0,
-              clkfbout_mult => 16,
-              clkout_divide => 32,
-              divclk_divide => 1);
-    else
-      report "Unsupported input frequency" severity failure;
---      return (clkin_period  => 0.0,
---              clkfbout_mult => 0,
---              clkout_divide => 0,
---              divclk_divide => 0);
-    end if;
-  end function gen_pll_settings;
+       constant bad_settings : pll_settings_t :=
+           (clkin_period  => 0.0,
+            clkfbout_mult => 2,
+            clkout_divide => 1,
+            divclk_divide => 1,
+            force_rst     => '1');
+    begin
+       case input_hz is
+       when 100000000 =>
+           case output_hz is
+           when 100000000 =>
+               return (clkin_period  => 10.0,
+                       clkfbout_mult => 16,
+                       clkout_divide => 16,
+                       divclk_divide => 1,
+                       force_rst     => '0');
+           when  50000000 =>
+               return (clkin_period  => 10.0,
+                       clkfbout_mult => 16,
+                       clkout_divide => 32,
+                       divclk_divide => 1,
+                       force_rst     => '0');
+           when others =>
+               report "Unsupported output frequency" severity failure;
+               return bad_settings;
+           end case;
+       when others =>
+           report "Unsupported input frequency" severity failure;
+           return bad_settings;
+       end case;
+    end function gen_pll_settings;
 
-  constant pll_settings : pll_settings_t := gen_pll_settings(clk_period_hz);
+    constant pll_settings : pll_settings_t := gen_pll_settings(clk_input_hz,
+                                                              clk_output_hz);
 begin
 
-  pll : PLLE2_BASE
-    generic map (
-      BANDWIDTH          => "OPTIMIZED",
-      CLKFBOUT_MULT      => pll_settings.clkfbout_mult,
-      CLKIN1_PERIOD      => pll_settings.clkin_period,
-      CLKOUT0_DIVIDE     => pll_settings.clkout_divide,
-      DIVCLK_DIVIDE      => pll_settings.divclk_divide,
-      STARTUP_WAIT       => "FALSE")
-    port map (
-      CLKOUT0  => pll_clk_out,
-      CLKOUT1  => open,
-      CLKOUT2  => open,
-      CLKOUT3  => open,
-      CLKOUT4  => open,
-      CLKOUT5  => open,
-      CLKFBOUT => clkfb,
-      LOCKED   => pll_locked_out,
-      CLKIN1   => ext_clk,
-      PWRDWN   => '0',
-      RST      => pll_rst_in,
-      CLKFBIN  => clkfb);
+    pll : PLLE2_BASE
+       generic map (
+           BANDWIDTH          => "OPTIMIZED",
+           CLKFBOUT_MULT      => pll_settings.clkfbout_mult,
+           CLKIN1_PERIOD      => pll_settings.clkin_period,
+           CLKOUT0_DIVIDE     => pll_settings.clkout_divide,
+           DIVCLK_DIVIDE      => pll_settings.divclk_divide,
+           STARTUP_WAIT       => "FALSE")
+       port map (
+           CLKOUT0  => pll_clk_out,
+           CLKOUT1  => open,
+           CLKOUT2  => open,
+           CLKOUT3  => open,
+           CLKOUT4  => open,
+           CLKOUT5  => open,
+           CLKFBOUT => clkfb,
+           LOCKED   => pll_locked_out,
+           CLKIN1   => ext_clk,
+           PWRDWN   => '0',
+           RST      => pll_rst_in or pll_settings.force_rst,
+           CLKFBIN  => clkfb);
 
 end architecture rtl;
index c6ed4ae9372e4148728ac393f6cdd4bb88b16a59..d73c802c5ece6e922c52a79b2ad4ee8b82c0a5dd 100644 (file)
@@ -5,7 +5,9 @@ entity toplevel is
     generic (
        MEMORY_SIZE   : positive := 524288;
        RAM_INIT_FILE : string   := "firmware.hex";
-       RESET_LOW     : boolean := true
+       RESET_LOW     : boolean  := true;
+       CLK_INPUT     : positive := 100000000;
+       CLK_FREQUENCY : positive := 100000000
        );
     port(
        ext_clk   : in  std_ulogic;
@@ -43,6 +45,10 @@ begin
            );
 
     clkgen: entity work.clock_generator
+       generic map(
+           CLK_INPUT_HZ => CLK_INPUT,
+           CLK_OUTPUT_HZ => CLK_FREQUENCY
+           )
        port map(
            ext_clk => ext_clk,
            pll_rst_in => pll_rst,
index b32148a0d22bfc56944bee9aa41aab6573e921b4..94ff0c163f63e298e0a41a4c2495c3108946915a 100644 (file)
@@ -81,7 +81,11 @@ targets:
   nexys_a7:
     default_tool: vivado
     filesets: [core, nexys_a7, soc, fpga, debug_xilinx]
-    parameters : [memory_size, ram_init_file]
+    parameters :
+      - memory_size
+      - ram_init_file
+      - clk_input
+      - clk_frequency
     tools:
       vivado: {part : xc7a100tcsg324-1}
     toplevel : toplevel
@@ -89,7 +93,11 @@ targets:
   nexys_video:
     default_tool: vivado
     filesets: [core, nexys_video, soc, fpga, debug_xilinx]
-    parameters : [memory_size, ram_init_file]
+    parameters :
+      - memory_size
+      - ram_init_file
+      - clk_input
+      - clk_frequency
     tools:
       vivado: {part : xc7a200tsbg484-1}
     toplevel : toplevel
@@ -97,7 +105,11 @@ targets:
   arty_a7-35:
     default_tool: vivado
     filesets: [core, arty_a7, soc, fpga, debug_xilinx]
-    parameters : [memory_size, ram_init_file]
+    parameters :
+      - memory_size
+      - ram_init_file
+      - clk_input
+      - clk_frequency
     tools:
       vivado: {part : xc7a35ticsg324-1L}
     toplevel : toplevel
@@ -105,7 +117,11 @@ targets:
   arty_a7-100:
     default_tool: vivado
     filesets: [core, arty_a7, soc, fpga, debug_xilinx]
-    parameters : [memory_size, ram_init_file]
+    parameters :
+      - memory_size
+      - ram_init_file
+      - clk_input
+      - clk_frequency
     tools:
       vivado: {part : xc7a100ticsg324-1L}
     toplevel : toplevel
@@ -113,7 +129,11 @@ targets:
   cmod_a7-35:
     default_tool: vivado
     filesets: [core, cmod_a7-35, soc, fpga, debug_xilinx]
-    parameters : [memory_size, ram_init_file, reset_low=false]
+    parameters :
+      - memory_size
+      - ram_init_file
+      - reset_low=false
+      - clk_input=12000000
     tools:
       vivado: {part : xc7a35tcpg236-1}
     toplevel : toplevel
@@ -139,3 +159,15 @@ parameters:
     datatype    : bool
     description : External reset button polarity
     paramtype   : generic
+
+  clk_input:
+    datatype    : int
+    description : Clock input frequency in HZ (for top-generic based boards)
+    paramtype   : generic
+    default     : 100000000
+
+  clk_frequency:
+    datatype    : int
+    description : Generated system clock frequency in HZ (for top-generic based boards)
+    paramtype   : generic
+    default     : 50000000