[top] - Integrate clkmgr

Signed-off-by: Timothy Chen <timothytim@google.com>

[clkmgr] - Integration updates

Signed-off-by: Timothy Chen <timothytim@google.com>

[clkmgr] resolve some lint warnings and comments

Signed-off-by: Timothy Chen <timothytim@google.com>

[clkmgr] - Add hjson exclusions for csr tests

- CLK_ENALBE / CLK_HINT can only be written in directed test cases

Signed-off-by: Timothy Chen <timothytim@google.com>

[top] - Update exclusions for clkmgr and pwrmgr

- Certain clkmgr/pwrmgr must be excluded from reset tests also.
  The pwrmgr register can trigger a low power entry, which kills allo
  clocks in the system and does not allow the test to proceed.

- Clock enable and hint registers also have the same problem.

Signed-off-by: Timothy Chen <timothytim@google.com>
diff --git a/hw/ip/clkmgr/data/clkmgr.hjson.tpl b/hw/ip/clkmgr/data/clkmgr.hjson.tpl
index 70af9b0..b9284d9 100644
--- a/hw/ip/clkmgr/data/clkmgr.hjson.tpl
+++ b/hw/ip/clkmgr/data/clkmgr.hjson.tpl
@@ -90,6 +90,9 @@
         }
 % endfor
       ]
+      // the CLK_ENABLE register cannot be written, otherwise there is the potential clocks could be
+      // disabled and the system will hang
+      tags: ["excl:CsrAllTests:CsrExclAll"]
     },
 
     { name: "CLK_HINTS",
@@ -116,6 +119,9 @@
         }
 % endfor
       ]
+      // the CLK_HINT register cannot be written, otherwise there is the potential clocks could be
+      // disabled and the system will hang
+      tags: ["excl:CsrAllTests:CsrExclAll"]
     },
 
     { name: "CLK_HINTS_STATUS",
diff --git a/hw/ip/clkmgr/data/clkmgr_pkg.sv.tpl b/hw/ip/clkmgr/data/clkmgr_pkg.sv.tpl
index 62ca076..23c5eca 100644
--- a/hw/ip/clkmgr/data/clkmgr_pkg.sv.tpl
+++ b/hw/ip/clkmgr/data/clkmgr_pkg.sv.tpl
@@ -15,7 +15,7 @@
   };
 
   typedef struct packed {
-% for clk in {**ft_clks, **hint_clks, **rg_clks, **sw_clks}:
+% for clk in {**hint_clks, **rg_clks, **sw_clks}:
   logic ${clk};
 % endfor
 
diff --git a/hw/ip/pwrmgr/data/pwrmgr.hjson b/hw/ip/pwrmgr/data/pwrmgr.hjson
index 668e142..a7e48f3 100644
--- a/hw/ip/pwrmgr/data/pwrmgr.hjson
+++ b/hw/ip/pwrmgr/data/pwrmgr.hjson
@@ -140,6 +140,8 @@
                 '''
             },
           ]
+          tags: [// The regwen for this reg is RO. CSR seq can't support to check this reg
+          "excl:CsrAllTests:CsrExclAll"]
         },
 
         { bits: "4",
@@ -204,8 +206,6 @@
           ]
         },
       ],
-      tags: [// The regwen for this reg is RO. CSR seq can't support to check this reg
-             "excl:CsrNonInitTests:CsrExclCheck"]
     },
 
     { name: "CFG_CDC_SYNC",
diff --git a/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson b/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson
index 0d54d67..be577fe 100644
--- a/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson
+++ b/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson
@@ -11,6 +11,11 @@
   datawidth: "32"
   clocks:
   {
+    hier_paths:
+    {
+      top: clkmgr_clocks.
+      ext: ""
+    }
     srcs:
     [
       {
@@ -30,17 +35,19 @@
     [
       {
         name: powerup
+        src: ext
         sw_cg: no
         unique: no
         clocks:
         {
-          clk_fixed_powerup: fixed
-          clk_main_powerup: main
-          clk_usb_48mhz_powerup: usb_48mhz
+          clk_fixed_i: fixed
+          clk_i: main
+          clk_usb_48mhz_i: usb_48mhz
         }
       }
       {
         name: trans
+        src: top
         sw_cg: hint
         unique: yes
         clocks:
@@ -51,6 +58,7 @@
       }
       {
         name: infra
+        src: top
         sw_cg: no
         unique: no
         clocks:
@@ -61,6 +69,7 @@
       }
       {
         name: secure
+        src: top
         sw_cg: no
         unique: no
         clocks:
@@ -71,6 +80,7 @@
       }
       {
         name: peri
+        src: top
         sw_cg: yes
         unique: no
         clocks:
@@ -81,6 +91,7 @@
       }
       {
         name: timers
+        src: top
         sw_cg: no
         unique: no
         clocks:
@@ -90,6 +101,7 @@
       }
       {
         name: proc
+        src: no
         sw_cg: no
         unique: no
         clocks:
@@ -159,6 +171,11 @@
         rst_ni: sys_fixed
       }
       base_addr: 0x40000000
+      clock_group: secure
+      clock_connections:
+      {
+        clk_i: clkmgr_clocks.clk_fixed_secure
+      }
       size: 0x1000
       bus_device: tlul
       bus_host: none
@@ -280,11 +297,6 @@
       ]
       alert_list: []
       scan: "false"
-      clock_group: secure
-      clock_connections:
-      {
-        clk_i: clk_fixed_secure
-      }
     }
     {
       name: gpio
@@ -299,6 +311,10 @@
         rst_ni: sys_fixed
       }
       base_addr: 0x40010000
+      clock_connections:
+      {
+        clk_i: clkmgr_clocks.clk_fixed_peri
+      }
       size: 0x1000
       bus_device: tlul
       bus_host: none
@@ -329,10 +345,6 @@
       ]
       alert_list: []
       scan: "false"
-      clock_connections:
-      {
-        clk_i: clk_fixed_peri
-      }
     }
     {
       name: spi_device
@@ -347,6 +359,10 @@
         rst_ni: spi_device
       }
       base_addr: 0x40020000
+      clock_connections:
+      {
+        clk_i: clkmgr_clocks.clk_fixed_peri
+      }
       size: 0x1000
       bus_device: tlul
       bus_host: none
@@ -454,10 +470,6 @@
       ]
       alert_list: []
       scan: "true"
-      clock_connections:
-      {
-        clk_i: clk_fixed_peri
-      }
     }
     {
       name: flash_ctrl
@@ -472,6 +484,10 @@
         rst_ni: lc
       }
       base_addr: 0x40030000
+      clock_connections:
+      {
+        clk_i: clkmgr_clocks.clk_main_infra
+      }
       size: 0x1000
       bus_device: tlul
       bus_host: none
@@ -569,10 +585,6 @@
           index: -1
         }
       ]
-      clock_connections:
-      {
-        clk_i: clk_main_infra
-      }
     }
     {
       name: rv_timer
@@ -587,6 +599,10 @@
         rst_ni: sys_fixed
       }
       base_addr: 0x40080000
+      clock_connections:
+      {
+        clk_i: clkmgr_clocks.clk_fixed_timers
+      }
       size: 0x1000
       bus_device: tlul
       bus_host: none
@@ -603,10 +619,6 @@
       ]
       alert_list: []
       scan: "false"
-      clock_connections:
-      {
-        clk_i: clk_fixed_timers
-      }
     }
     {
       name: aes
@@ -621,6 +633,10 @@
         rst_ni: sys
       }
       base_addr: 0x40110000
+      clock_connections:
+      {
+        clk_i: clkmgr_clocks.clk_main_aes
+      }
       size: 0x1000
       bus_device: tlul
       bus_host: none
@@ -630,10 +646,6 @@
       interrupt_list: []
       alert_list: []
       scan: "false"
-      clock_connections:
-      {
-        clk_i: clk_main_aes
-      }
     }
     {
       name: hmac
@@ -648,6 +660,10 @@
         rst_ni: sys
       }
       base_addr: 0x40120000
+      clock_connections:
+      {
+        clk_i: clkmgr_clocks.clk_main_hmac
+      }
       size: 0x1000
       bus_device: tlul
       bus_host: none
@@ -703,10 +719,6 @@
         }
       ]
       scan: "false"
-      clock_connections:
-      {
-        clk_i: clk_main_hmac
-      }
     }
     {
       name: rv_plic
@@ -722,6 +734,10 @@
       }
       base_addr: 0x40090000
       generated: "true"
+      clock_connections:
+      {
+        clk_i: clkmgr_clocks.clk_main_secure
+      }
       size: 0x1000
       bus_device: tlul
       bus_host: none
@@ -731,10 +747,6 @@
       interrupt_list: []
       alert_list: []
       scan: "false"
-      clock_connections:
-      {
-        clk_i: clk_main_secure
-      }
     }
     {
       name: pinmux
@@ -753,6 +765,11 @@
       }
       base_addr: 0x40070000
       generated: "true"
+      clock_connections:
+      {
+        clk_i: clkmgr_clocks.clk_main_secure
+        clk_aon_i: clkmgr_clocks.clk_fixed_secure
+      }
       size: 0x1000
       bus_device: tlul
       bus_host: none
@@ -792,11 +809,6 @@
           index: -1
         }
       ]
-      clock_connections:
-      {
-        clk_i: clk_main_secure
-        clk_aon_i: clk_fixed_secure
-      }
     }
     {
       name: alert_handler
@@ -818,6 +830,10 @@
         AccuCntDw: 16
         LfsrSeed: 0x7FFFFFFF
       }
+      clock_connections:
+      {
+        clk_i: clkmgr_clocks.clk_main_secure
+      }
       size: 0x1000
       bus_device: tlul
       bus_host: none
@@ -877,15 +893,10 @@
       ]
       alert_list: []
       scan: "false"
-      clock_connections:
-      {
-        clk_i: clk_main_secure
-      }
     }
     {
       name: pwrmgr
       type: pwrmgr
-      clock: main
       clock_srcs:
       {
         clk_i: fixed
@@ -898,7 +909,11 @@
         rst_slow_ni: por
       }
       base_addr: 0x400A0000
-      generated: "true"
+      clock_connections:
+      {
+        clk_i: clk_fixed_i
+        clk_slow_i: clk_fixed_i
+      }
       size: 0x1000
       bus_device: tlul
       bus_host: none
@@ -946,11 +961,13 @@
         }
         {
           struct: pwr_clk
-          type: uni
+          type: req_rsp
           name: pwr_clk
           act: req
           package: pwrmgr_pkg
           inst_name: pwrmgr
+          width: 1
+          top_signame: pwrmgr_pwr_clk
           index: -1
         }
         {
@@ -1001,16 +1018,10 @@
           index: -1
         }
       ]
-      clock_connections:
-      {
-        clk_i: clk_fixed_powerup
-        clk_slow_i: clk_fixed_powerup
-      }
     }
     {
       name: rstmgr
       type: rstmgr
-      clock: main
       clock_srcs:
       {
         clk_i: fixed
@@ -1024,7 +1035,13 @@
         rst_ni: rst_ni
       }
       base_addr: 0x400B0000
-      generated: "true"
+      clock_connections:
+      {
+        clk_i: clk_fixed_i
+        clk_main_i: clk_i
+        clk_fixed_i: clk_fixed_i
+        clk_usb_i: clk_usb_48mhz_i
+      }
       size: 0x1000
       bus_device: tlul
       bus_host: none
@@ -1088,13 +1105,86 @@
           index: -1
         }
       ]
+    }
+    {
+      name: clkmgr
+      type: clkmgr
+      clock_srcs:
+      {
+        clk_i: fixed
+        clk_main_i: main
+        clk_fixed_i: fixed
+        clk_usb_48mhz_i: usb_48mhz
+      }
+      clock_group: powerup
+      reset_connections:
+      {
+        rst_ni: por
+        rst_main_ni: por
+        rst_fixed_ni: por
+        rst_usb_48mhz_ni: por
+      }
+      base_addr: 0x400C0000
+      generated: "true"
       clock_connections:
       {
-        clk_i: clk_fixed_powerup
-        clk_main_i: clk_main_powerup
-        clk_fixed_i: clk_fixed_powerup
-        clk_usb_i: clk_usb_48mhz_powerup
+        clk_i: clk_fixed_i
+        clk_main_i: clk_i
+        clk_fixed_i: clk_fixed_i
+        clk_usb_48mhz_i: clk_usb_48mhz_i
       }
+      size: 0x1000
+      bus_device: tlul
+      bus_host: none
+      available_input_list: []
+      available_output_list: []
+      available_inout_list: []
+      interrupt_list: []
+      alert_list: []
+      scan: "false"
+      inter_signal_list:
+      [
+        {
+          struct: clkmgr_out
+          type: uni
+          name: clocks
+          act: req
+          package: clkmgr_pkg
+          inst_name: clkmgr
+          width: 1
+          top_signame: clkmgr_clocks
+          index: -1
+        }
+        {
+          struct: pwr_clk
+          type: req_rsp
+          name: pwr
+          act: rsp
+          inst_name: clkmgr
+          width: 1
+          package: pwrmgr_pkg
+          top_signame: pwrmgr_pwr_clk
+          index: -1
+        }
+        {
+          struct: clk_dft
+          type: uni
+          name: dft
+          act: rcv
+          package: clkmgr_pkg
+          inst_name: clkmgr
+          index: -1
+        }
+        {
+          struct: clk_hint_status
+          type: uni
+          name: status
+          act: rcv
+          package: clkmgr_pkg
+          inst_name: clkmgr
+          index: -1
+        }
+      ]
     }
     {
       name: nmi_gen
@@ -1109,6 +1199,10 @@
         rst_ni: sys
       }
       base_addr: 0x40140000
+      clock_connections:
+      {
+        clk_i: clkmgr_clocks.clk_main_secure
+      }
       size: 0x1000
       bus_device: tlul
       bus_host: none
@@ -1168,10 +1262,6 @@
       ]
       alert_list: []
       scan: "false"
-      clock_connections:
-      {
-        clk_i: clk_main_secure
-      }
     }
     {
       name: usbdev
@@ -1188,6 +1278,11 @@
         rst_usb_48mhz_ni: usb
       }
       base_addr: 0x40150000
+      clock_connections:
+      {
+        clk_i: clkmgr_clocks.clk_fixed_peri
+        clk_usb_48mhz_i: clkmgr_clocks.clk_usb_48mhz_peri
+      }
       size: 0x1000
       bus_device: tlul
       bus_host: none
@@ -1437,11 +1532,6 @@
       ]
       alert_list: []
       scan: "false"
-      clock_connections:
-      {
-        clk_i: clk_fixed_peri
-        clk_usb_48mhz_i: clk_usb_48mhz_peri
-      }
     }
   ]
   memory:
@@ -1463,7 +1553,7 @@
       size: 0x4000
       clock_connections:
       {
-        clk_i: clk_main_infra
+        clk_i: clkmgr_clocks.clk_main_infra
       }
     }
     {
@@ -1482,7 +1572,7 @@
       size: 0x10000
       clock_connections:
       {
-        clk_i: clk_main_infra
+        clk_i: clkmgr_clocks.clk_main_infra
       }
     }
     {
@@ -1516,7 +1606,7 @@
       ]
       clock_connections:
       {
-        clk_i: clk_main_infra
+        clk_i: clkmgr_clocks.clk_main_infra
       }
     }
   ]
@@ -1532,12 +1622,17 @@
       [
         rstmgr.pwr
       ]
+      pwrmgr.pwr_clk:
+      [
+        clkmgr.pwr
+      ]
     }
     top:
     [
       rstmgr.resets
       rstmgr.cpu
       pwrmgr.pwr_cpu
+      clkmgr.clocks
     ]
     external: []
   }
@@ -1559,8 +1654,8 @@
       }
       clock_connections:
       {
-        clk_main_i: clk_main_infra
-        clk_fixed_i: clk_fixed_infra
+        clk_main_i: clkmgr_clocks.clk_main_infra
+        clk_fixed_i: clkmgr_clocks.clk_fixed_infra
       }
       connections:
       {
@@ -1739,6 +1834,10 @@
               base_addr: 0x400B0000
               size_byte: 0x1000
             }
+            {
+              base_addr: 0x400C0000
+              size_byte: 0x1000
+            }
           ]
         }
         {
@@ -1875,7 +1974,7 @@
       }
       clock_connections:
       {
-        clk_peri_i: clk_fixed_infra
+        clk_peri_i: clkmgr_clocks.clk_fixed_infra
       }
       connections:
       {
@@ -1888,6 +1987,7 @@
           usbdev
           pwrmgr
           rstmgr
+          clkmgr
         ]
       }
       nodes:
@@ -2021,6 +2121,23 @@
           xbar: false
           pipeline_byp: "true"
         }
+        {
+          name: clkmgr
+          type: device
+          clock: clk_peri_i
+          reset: rst_peri_ni
+          pipeline: "false"
+          inst_type: clkmgr
+          addr_range:
+          [
+            {
+              base_addr: 0x400C0000
+              size_byte: 0x1000
+            }
+          ]
+          xbar: false
+          pipeline_byp: "true"
+        }
       ]
       clock: clk_peri_i
     }
@@ -3036,11 +3153,13 @@
       }
       {
         struct: pwr_clk
-        type: uni
+        type: req_rsp
         name: pwr_clk
         act: req
         package: pwrmgr_pkg
         inst_name: pwrmgr
+        width: 1
+        top_signame: pwrmgr_pwr_clk
         index: -1
       }
       {
@@ -3142,6 +3261,46 @@
         index: -1
       }
       {
+        struct: clkmgr_out
+        type: uni
+        name: clocks
+        act: req
+        package: clkmgr_pkg
+        inst_name: clkmgr
+        width: 1
+        top_signame: clkmgr_clocks
+        index: -1
+      }
+      {
+        struct: pwr_clk
+        type: req_rsp
+        name: pwr
+        act: rsp
+        inst_name: clkmgr
+        width: 1
+        package: pwrmgr_pkg
+        top_signame: pwrmgr_pwr_clk
+        index: -1
+      }
+      {
+        struct: clk_dft
+        type: uni
+        name: dft
+        act: rcv
+        package: clkmgr_pkg
+        inst_name: clkmgr
+        index: -1
+      }
+      {
+        struct: clk_hint_status
+        type: uni
+        name: status
+        act: rcv
+        package: clkmgr_pkg
+        inst_name: clkmgr
+        index: -1
+      }
+      {
         struct: flash
         type: req_rsp
         name: flash_ctrl
@@ -3185,6 +3344,20 @@
         type: req_rsp
       }
       {
+        package: pwrmgr_pkg
+        struct: pwr_clk_req
+        signame: pwrmgr_pwr_clk_req
+        width: 1
+        type: req_rsp
+      }
+      {
+        package: pwrmgr_pkg
+        struct: pwr_clk_rsp
+        signame: pwrmgr_pwr_clk_rsp
+        width: 1
+        type: req_rsp
+      }
+      {
         package: rstmgr_pkg
         struct: rstmgr_out
         signame: rstmgr_resets
@@ -3205,6 +3378,13 @@
         width: 1
         type: uni
       }
+      {
+        package: clkmgr_pkg
+        struct: clkmgr_out
+        signame: clkmgr_clocks
+        width: 1
+        type: uni
+      }
     ]
   }
 }
\ No newline at end of file
diff --git a/hw/top_earlgrey/data/top_earlgrey.hjson b/hw/top_earlgrey/data/top_earlgrey.hjson
index a2e98d2..a8cee1e 100644
--- a/hw/top_earlgrey/data/top_earlgrey.hjson
+++ b/hw/top_earlgrey/data/top_earlgrey.hjson
@@ -9,10 +9,17 @@
   datawidth: "32",  # 32-bit datawidth
 
   // This is the clock data strcture of the design.
+  // The hier path refers to the clock reference path (struct / port)
+  //   - The top/ext desgination follows the same scheme as inter-module
   // The src key indicates the raw clock sources in the design
   // The groups key indicates the various clock groupings in the design
   clocks: {
 
+    hier_paths: {
+      top: "clkmgr_clocks.", // top level is a struct
+      ext: "",               // ext is a port of the clock name
+    },
+
     srcs: [
       { name: "main",      freq: "100000000" }
       { name: "fixed",     freq: "100000000" }
@@ -22,6 +29,10 @@
     // Clock Group attributes
     // name: name of group.
     //
+    // src: The hierarchical source of the clock
+    // "ext"  - clock is supplied from a port of the top module
+    // "top"  - clock is supplied from a net inside the top module
+    //
     // sw_cfg: whether software is allowed to gate the clock
     // "no"   - software is not allowed to gate clocks
     // "yes"  - software is allowed to gate clocks
@@ -38,13 +49,14 @@
     // The proc group is not peripheral, and direclty hardwired
 
     groups: [
-      { name: "powerup", sw_cg: "no"                   }
-      { name: "trans",   sw_cg: "hint", unique: "yes", }
-      { name: "infra",   sw_cg: "no",                  }
-      { name: "secure",  sw_cg: "no"                   }
-      { name: "peri",    sw_cg: "yes",  unique: "no"   }
-      { name: "timers",  sw_cg: "no"                   }
+      { name: "powerup", src:"ext", sw_cg: "no"                   }
+      { name: "trans",   src:"top", sw_cg: "hint", unique: "yes", }
+      { name: "infra",   src:"top", sw_cg: "no",                  }
+      { name: "secure",  src:"top", sw_cg: "no"                   }
+      { name: "peri",    src:"top", sw_cg: "yes",  unique: "no"   }
+      { name: "timers",  src:"top", sw_cg: "no"                   }
       { name: "proc",
+        src: "no"
         sw_cg: "no"
         unique: "no"
         clocks: {
@@ -174,20 +186,25 @@
     }
     { name: "pwrmgr",
       type: "pwrmgr",
-      clock: "main",
       clock_srcs: {clk_i: "fixed", clk_slow_i: "fixed"},
       clock_group: "powerup",
       reset_connections: {rst_ni: "por", rst_slow_ni: "por"},
       base_addr: "0x400A0000",
-      generated: "true"
+
     },
     { name: "rstmgr",
       type: "rstmgr",
-      clock: "main",
       clock_srcs: {clk_i: "fixed", clk_main_i: "main", clk_fixed_i: "fixed", clk_usb_i: "usb_48mhz"},
       clock_group: "powerup",
       reset_connections: {rst_ni: "rst_ni"},
       base_addr: "0x400B0000",
+    },
+    { name: "clkmgr",
+      type: "clkmgr",
+      clock_srcs: {clk_i: "fixed", clk_main_i: "main", clk_fixed_i: "fixed", clk_usb_48mhz_i: "usb_48mhz"},
+      clock_group: "powerup",
+      reset_connections: {rst_ni: "por", rst_main_ni: "por", rst_fixed_ni: "por", rst_usb_48mhz_ni: "por"},
+      base_addr: "0x400C0000",
       generated: "true"
     },
     // dummy module to capture the alert handler escalation signals
@@ -255,12 +272,13 @@
     'connect': {
       'flash_ctrl.flash': ['eflash.flash_ctrl']
       'pwrmgr.pwr_rst'  : ['rstmgr.pwr'],
+      'pwrmgr.pwr_clk'  : ['clkmgr.pwr'],
     }
 
     // top is to connect to top net/struct.
     // It defines the signal in the top and connect from the module,
     // use of the signal is up to top template
-    'top': ['rstmgr.resets', 'rstmgr.cpu', 'pwrmgr.pwr_cpu'],
+    'top': ['rstmgr.resets', 'rstmgr.cpu', 'pwrmgr.pwr_cpu', 'clkmgr.clocks'],
 
     // ext is to create port in the top.
     'external': [],
diff --git a/hw/top_earlgrey/data/top_earlgrey.sv.tpl b/hw/top_earlgrey/data/top_earlgrey.sv.tpl
index 8d36e10..41386d4 100644
--- a/hw/top_earlgrey/data/top_earlgrey.sv.tpl
+++ b/hw/top_earlgrey/data/top_earlgrey.sv.tpl
@@ -25,7 +25,9 @@
 max_sigwidth = len("{}".format(max_sigwidth))
 
 clks_attr = top['clocks']
-
+cpu_clk = top['clocks']['hier_paths']['top'] + "clk_proc_main"
+cpu_rst = top["reset_paths"]["sys"]
+dm_rst = top["reset_paths"]["lc"]
 %>\
 module top_${top["name"]} #(
   parameter bit IbexPipeLine = 0
@@ -131,13 +133,6 @@
   % endfor
 % endfor
 
-  //clock wires declaration
-% for clock_group in clks_attr['groups']:
-  % for k in clock_group['clocks']:
-  logic ${k};
-  % endfor
-% endfor
-
   // Signals
   logic [${num_mio_inputs + num_mio_inouts - 1}:0] mio2periph;
   logic [${num_mio_outputs + num_mio_inouts - 1}:0] periph2mio;
@@ -218,14 +213,6 @@
   ${lib.im_defname(sig)} ${lib.bitarray(sig["width"],1)} ${sig["signame"]};
 % endfor
 
-  // Clock assignments
-  // These assignments are temporary until the creation of the clock controller
-% for clock_group in clks_attr['groups']:
-  % for k,v in clock_group['clocks'].items():
-  assign ${k} = ${lib.get_clk_name(v)};
-  % endfor
-% endfor
-
   // Non-debug module reset == reset for everything except for the debug module
   logic ndmreset_req;
 
@@ -250,8 +237,8 @@
     .PipeLine                 (IbexPipeLine)
   ) u_rv_core_ibex (
     // clock and reset
-    .clk_i                (clk_proc_main),
-    .rst_ni               (${top["reset_paths"]["sys"]}),
+    .clk_i                (${cpu_clk}),
+    .rst_ni               (${cpu_rst}),
     .test_en_i            (1'b0),
     // static pinning
     .hart_id_i            (32'b0),
@@ -281,8 +268,8 @@
     .NrHarts     (1),
     .IdcodeValue (JTAG_IDCODE)
   ) u_dm_top (
-    .clk_i         (clk_proc_main),
-    .rst_ni        (${top["reset_paths"]["lc"]}),
+    .clk_i         (${cpu_clk}),
+    .rst_ni        (${dm_rst}),
     .testmode_i    (1'b0),
     .ndmreset_o    (ndmreset_req),
     .dmactive_o    (),
diff --git a/hw/top_earlgrey/data/xbar_peri.hjson b/hw/top_earlgrey/data/xbar_peri.hjson
index 8511c44..7294aeb 100644
--- a/hw/top_earlgrey/data/xbar_peri.hjson
+++ b/hw/top_earlgrey/data/xbar_peri.hjson
@@ -53,9 +53,15 @@
       clock:     "clk_peri_i",
       reset:     "rst_peri_ni",
       pipeline: "false"
+    },
+    { name:      "clkmgr",
+      type:      "device",
+      clock:     "clk_peri_i",
+      reset:     "rst_peri_ni",
+      pipeline: "false"
     }
   ],
   connections: {
-    main:  ["uart", "gpio", "spi_device", "rv_timer", "usbdev", "pwrmgr", "rstmgr"],
+    main:  ["uart", "gpio", "spi_device", "rv_timer", "usbdev", "pwrmgr", "rstmgr", "clkmgr"],
   },
 }
diff --git a/hw/top_earlgrey/ip/clkmgr/clkmgr.core b/hw/top_earlgrey/ip/clkmgr/clkmgr.core
new file mode 100644
index 0000000..9e47786
--- /dev/null
+++ b/hw/top_earlgrey/ip/clkmgr/clkmgr.core
@@ -0,0 +1,25 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:top_earlgrey:clkmgr:0.1"
+description: "Clock manager component without the generated portions"
+
+filesets:
+  files_rtl:
+    depend:
+      - lowrisc:ip:tlul
+      - lowrisc:prim:all
+      - lowrisc:prim:clock_gating
+      - lowrisc:ip:pwrmgr
+    files:
+      - rtl/autogen/clkmgr_pkg.sv
+      - rtl/autogen/clkmgr_reg_pkg.sv
+      - rtl/autogen/clkmgr_reg_top.sv
+      - rtl/autogen/clkmgr.sv
+    file_type: systemVerilogSource
+
+targets:
+  default: &default_target
+    filesets:
+      - files_rtl
diff --git a/hw/top_earlgrey/ip/clkmgr/data/autogen/clkmgr.hjson b/hw/top_earlgrey/ip/clkmgr/data/autogen/clkmgr.hjson
new file mode 100644
index 0000000..8c5075f
--- /dev/null
+++ b/hw/top_earlgrey/ip/clkmgr/data/autogen/clkmgr.hjson
@@ -0,0 +1,172 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// ------------------- W A R N I N G: A U T O - G E N E R A T E D   C O D E !! -------------------//
+// PLEASE DO NOT HAND-EDIT THIS FILE. IT HAS BEEN AUTO-GENERATED WITH THE FOLLOWING COMMAND:
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+// TODO: This module is only a draft implementation that covers most of the rstmgr
+// functoinality but is incomplete
+
+
+
+# CLKMGR register template
+#
+{
+  name: "CLKMGR",
+  clock_primary: "clk_i",
+  other_clock_list: [
+    "clk_main_i",
+    "clk_fixed_i",
+    "clk_usb_48mhz_i",
+  ],
+  reset_primary: "rst_ni",
+  other_reset_list: [
+    "rst_main_ni"
+    "rst_fixed_ni"
+    "rst_usb_48mhz_ni"
+  ]
+  bus_device: "tlul",
+  regwidth: "32",
+  param_list: [
+    { name: "NumGroups",
+      desc: "Number of clock groups",
+      type: "int",
+      default: "7",
+      local: "true"
+    },
+  ],
+
+  // Define rstmgr struct package
+  inter_signal_list: [
+    { struct:  "clkmgr_out",
+      type:    "uni",
+      name:    "clocks",
+      act:     "req",
+      package: "clkmgr_pkg",
+    },
+
+    { struct:  "pwr_clk",
+      type:    "req_rsp",
+      name:    "pwr",
+      act:     "rsp",
+    },
+
+    { struct:  "clk_dft",
+      type:    "uni",
+      name:    "dft",
+      act:     "rcv",
+      package: "clkmgr_pkg", // This should be moved elsewhere later
+    },
+
+    { struct:  "clk_hint_status",
+      type:    "uni",
+      name:    "status",
+      act:     "rcv",
+      package: "clkmgr_pkg",
+    },
+  ],
+
+
+  registers: [
+    { name: "CLK_ENABLES",
+      desc: '''
+        Clock enable for software gateable clocks.
+        These clocks are direclty controlled by software.
+      ''',
+      swaccess: "rw",
+      hwaccess: "hro",
+      fields: [
+        {
+          bits: "0",
+          name: "CLK_FIXED_PERI_EN",
+          resval: 1,
+          desc: '''
+            0 CLK_FIXED_PERI is disabled.
+            1 CLK_FIXED_PERI is enabled.
+          '''
+        }
+        {
+          bits: "1",
+          name: "CLK_USB_48MHZ_PERI_EN",
+          resval: 1,
+          desc: '''
+            0 CLK_USB_48MHZ_PERI is disabled.
+            1 CLK_USB_48MHZ_PERI is enabled.
+          '''
+        }
+      ]
+      // the CLK_ENABLE register cannot be written, otherwise there is the potential clocks could be
+      // disabled and the system will hang
+      tags: ["excl:CsrAllTests:CsrExclWrite:CsrExclWriteCheck"]
+    },
+
+    { name: "CLK_HINTS",
+      desc: '''
+        Clock hint for software gateable clocks.
+        These clocks are not fully controlled by software.
+
+        For disable, software only provides a hint, and hardware determines the final clock state based on the
+        hint and whether the block in question is idle.
+
+      ''',
+      swaccess: "rw",
+      hwaccess: "hro",
+      fields: [
+        {
+          bits: "0",
+          name: "CLK_MAIN_AES_HINT",
+          resval: 1,
+          desc: '''
+            0 CLK_MAIN_AES can be disabled.
+            1 CLK_MAIN_AES is enabled.
+          '''
+        }
+        {
+          bits: "1",
+          name: "CLK_MAIN_HMAC_HINT",
+          resval: 1,
+          desc: '''
+            0 CLK_MAIN_HMAC can be disabled.
+            1 CLK_MAIN_HMAC is enabled.
+          '''
+        }
+      ]
+      // the CLK_HINT register cannot be written, otherwise there is the potential clocks could be
+      // disabled and the system will hang
+      tags: ["excl:CsrAllTests:CsrExclWrite:CsrExclWriteCheck"]
+    },
+
+    { name: "CLK_HINTS_STATUS",
+      desc: '''
+        Since the final state of !!CLK_HINTS is not always determined by software,
+        this register provides read feedback for the current clock state.
+
+      ''',
+      swaccess: "ro",
+      hwaccess: "hwo",
+      fields: [
+        {
+          bits: "0",
+          name: "CLK_MAIN_AES_VAL",
+          resval: 1,
+          desc: '''
+            0 CLK_MAIN_AES is disabled.
+            1 CLK_MAIN_AES is enabled.
+          '''
+        }
+        {
+          bits: "1",
+          name: "CLK_MAIN_HMAC_VAL",
+          resval: 1,
+          desc: '''
+            0 CLK_MAIN_HMAC is disabled.
+            1 CLK_MAIN_HMAC is enabled.
+          '''
+        }
+      ]
+    },
+  ]
+}
diff --git a/hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr.sv b/hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr.sv
new file mode 100644
index 0000000..45cbec7
--- /dev/null
+++ b/hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr.sv
@@ -0,0 +1,257 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// ------------------- W A R N I N G: A U T O - G E N E R A T E D   C O D E !! -------------------//
+// PLEASE DO NOT HAND-EDIT THIS FILE. IT HAS BEEN AUTO-GENERATED WITH THE FOLLOWING COMMAND:
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// The overall clock manager
+
+`include "prim_assert.sv"
+
+
+
+module clkmgr import clkmgr_pkg::*; (
+  // Primary module clocks
+  input clk_i,
+  input rst_ni,
+  input clk_main_i,
+  input rst_main_ni,
+  input clk_fixed_i,
+  input rst_fixed_ni,
+  input clk_usb_48mhz_i,
+  input rst_usb_48mhz_ni,
+
+  // Bus Interface
+  input tlul_pkg::tl_h2d_t tl_i,
+  output tlul_pkg::tl_d2h_t tl_o,
+
+  // pwrmgr interface
+  input pwrmgr_pkg::pwr_clk_req_t pwr_i,
+  output pwrmgr_pkg::pwr_clk_rsp_t pwr_o,
+
+  // dft interface
+  input clk_dft_t dft_i,
+
+  // idle hints
+  input clk_hint_status_t status_i,
+
+  // clock output interface
+  output clkmgr_out_t clocks_o
+
+);
+
+  ////////////////////////////////////////////////////
+  // Register Interface
+  ////////////////////////////////////////////////////
+
+  clkmgr_reg_pkg::clkmgr_reg2hw_t reg2hw;
+  clkmgr_reg_pkg::clkmgr_hw2reg_t hw2reg;
+
+  clkmgr_reg_top i_reg (
+    .clk_i,
+    .rst_ni,
+    .tl_i,
+    .tl_o,
+    .reg2hw,
+    .hw2reg,
+    .devmode_i(1'b1)
+  );
+
+
+  ////////////////////////////////////////////////////
+  // Root gating
+  ////////////////////////////////////////////////////
+
+  // the rst_ni connection below is incorrect, need to find a proper reset in the sequence to use
+  // if the clkmgr is always on, can use por synced directly
+  // if not, then need to generate something ahead of lc/sys
+
+  logic async_roots_en;
+  logic roots_en_q2, roots_en_q1, roots_en_d;
+  logic clk_main_root;
+  logic clk_main_en;
+  logic clk_fixed_root;
+  logic clk_fixed_en;
+  logic clk_usb_48mhz_root;
+  logic clk_usb_48mhz_en;
+
+  prim_clock_gating_sync i_main_cg (
+    .clk_i(clk_main_i),
+    .rst_ni(rst_main_ni),
+    .test_en_i(dft_i.test_en),
+    .async_en_i(pwr_i.ip_clk_en),
+    .en_o(clk_main_en),
+    .clk_o(clk_main_root)
+  );
+  prim_clock_gating_sync i_fixed_cg (
+    .clk_i(clk_fixed_i),
+    .rst_ni(rst_fixed_ni),
+    .test_en_i(dft_i.test_en),
+    .async_en_i(pwr_i.ip_clk_en),
+    .en_o(clk_fixed_en),
+    .clk_o(clk_fixed_root)
+  );
+  prim_clock_gating_sync i_usb_48mhz_cg (
+    .clk_i(clk_usb_48mhz_i),
+    .rst_ni(rst_usb_48mhz_ni),
+    .test_en_i(dft_i.test_en),
+    .async_en_i(pwr_i.ip_clk_en),
+    .en_o(clk_usb_48mhz_en),
+    .clk_o(clk_usb_48mhz_root)
+  );
+
+  // an async OR of all the synchronized enables
+  assign async_roots_en =
+    clk_main_en |
+    clk_fixed_en |
+    clk_usb_48mhz_en;
+
+  // Sync the OR back into clkmgr domain for feedback to pwrmgr.
+  // Since the signal is combo / converged on the other side, de-bounce
+  // the signal prior to output
+  prim_flop_2sync #(
+    .Width(1)
+  ) i_roots_en_sync (
+    .clk_i,
+    .rst_ni,
+    .d(async_roots_en),
+    .q(roots_en_d)
+  );
+
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) begin
+      roots_en_q1 <= 1'b0;
+      roots_en_q2 <= 1'b0;
+    end else begin
+      roots_en_q1 <= roots_en_d;
+
+      if (roots_en_q1 == roots_en_d) begin
+        roots_en_q2 <= roots_en_q1;
+      end
+    end
+  end
+
+  assign pwr_o.roots_en = roots_en_q2;
+
+  ////////////////////////////////////////////////////
+  // Clocks with only root gate
+  ////////////////////////////////////////////////////
+  assign clocks_o.clk_main_infra = clk_main_root;
+  assign clocks_o.clk_fixed_infra = clk_fixed_root;
+  assign clocks_o.clk_fixed_secure = clk_fixed_root;
+  assign clocks_o.clk_main_secure = clk_main_root;
+  assign clocks_o.clk_fixed_timers = clk_fixed_root;
+  assign clocks_o.clk_proc_main = clk_main_root;
+
+  ////////////////////////////////////////////////////
+  // Software direct control group
+  ////////////////////////////////////////////////////
+
+  // the rst_ni connection below is incorrect, need to find a proper reset in the sequence to use
+  // if the clkmgr is always on, can use por synced directly
+  // if not, then need to generate something ahead of lc/sys
+  logic clk_fixed_peri_sw_en;
+  logic clk_usb_48mhz_peri_sw_en;
+
+  prim_flop_2sync #(
+    .Width(1)
+  ) i_clk_fixed_peri_sw_en_sync (
+    .clk_i(clk_fixed_i),
+    .rst_ni(rst_fixed_ni),
+    .d(reg2hw.clk_enables.clk_fixed_peri_en.q),
+    .q(clk_fixed_peri_sw_en)
+  );
+
+  prim_clock_gating i_clk_fixed_peri_cg (
+    .clk_i(clk_fixed_i),
+    .en_i(clk_fixed_peri_sw_en & clk_fixed_en),
+    .test_en_i(dft_i.test_en),
+    .clk_o(clocks_o.clk_fixed_peri)
+  );
+
+  prim_flop_2sync #(
+    .Width(1)
+  ) i_clk_usb_48mhz_peri_sw_en_sync (
+    .clk_i(clk_usb_48mhz_i),
+    .rst_ni(rst_usb_48mhz_ni),
+    .d(reg2hw.clk_enables.clk_usb_48mhz_peri_en.q),
+    .q(clk_usb_48mhz_peri_sw_en)
+  );
+
+  prim_clock_gating i_clk_usb_48mhz_peri_cg (
+    .clk_i(clk_usb_48mhz_i),
+    .en_i(clk_usb_48mhz_peri_sw_en & clk_usb_48mhz_en),
+    .test_en_i(dft_i.test_en),
+    .clk_o(clocks_o.clk_usb_48mhz_peri)
+  );
+
+
+  ////////////////////////////////////////////////////
+  // Software hint group
+  // The idle hint feedback is assumed to be synchronous to the
+  // clock target
+  ////////////////////////////////////////////////////
+
+  // the rst_ni connection below is incorrect, need to find a proper reset in the sequence to use
+  // if the clkmgr is always on, can use por synced directly
+  // if not, then need to generate something ahead of lc/sys
+
+  logic clk_main_aes_hint;
+  logic clk_main_aes_en;
+  logic clk_main_hmac_hint;
+  logic clk_main_hmac_en;
+
+  assign clk_main_aes_en = clk_main_aes_hint | ~status_i.idle[0];
+
+  prim_flop_2sync #(
+    .Width(1)
+  ) i_clk_main_aes_hint_sync (
+    .clk_i(clk_main_i),
+    .rst_ni(rst_main_ni),
+    .d(reg2hw.clk_hints.clk_main_aes_hint.q),
+    .q(clk_main_aes_hint)
+  );
+
+  prim_clock_gating i_clk_main_aes_cg (
+    .clk_i(clk_main_i),
+    .en_i(clk_main_aes_en & clk_main_en),
+    .test_en_i(dft_i.test_en),
+    .clk_o(clocks_o.clk_main_aes)
+  );
+
+  assign clk_main_hmac_en = clk_main_hmac_hint | ~status_i.idle[1];
+
+  prim_flop_2sync #(
+    .Width(1)
+  ) i_clk_main_hmac_hint_sync (
+    .clk_i(clk_main_i),
+    .rst_ni(rst_main_ni),
+    .d(reg2hw.clk_hints.clk_main_hmac_hint.q),
+    .q(clk_main_hmac_hint)
+  );
+
+  prim_clock_gating i_clk_main_hmac_cg (
+    .clk_i(clk_main_i),
+    .en_i(clk_main_hmac_en & clk_main_en),
+    .test_en_i(dft_i.test_en),
+    .clk_o(clocks_o.clk_main_hmac)
+  );
+
+
+  // state readback
+  assign hw2reg.clk_hints_status.clk_main_aes_val.de = 1'b1;
+  assign hw2reg.clk_hints_status.clk_main_aes_val.d = clk_main_aes_en;
+  assign hw2reg.clk_hints_status.clk_main_hmac_val.de = 1'b1;
+  assign hw2reg.clk_hints_status.clk_main_hmac_val.d = clk_main_hmac_en;
+
+
+  ////////////////////////////////////////////////////
+  // Assertions
+  ////////////////////////////////////////////////////
+
+
+endmodule // rstmgr
diff --git a/hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr_pkg.sv b/hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr_pkg.sv
new file mode 100644
index 0000000..09dd868
--- /dev/null
+++ b/hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr_pkg.sv
@@ -0,0 +1,42 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// ------------------- W A R N I N G: A U T O - G E N E R A T E D   C O D E !! -------------------//
+// PLEASE DO NOT HAND-EDIT THIS FILE. IT HAS BEEN AUTO-GENERATED WITH THE FOLLOWING COMMAND:
+
+
+package clkmgr_pkg;
+
+  typedef struct packed {
+    logic test_en;
+  } clk_dft_t;
+
+  parameter clk_dft_t CLK_DFT_DEFAULT = '{
+    test_en: 1'b0
+  };
+
+  typedef struct packed {
+  logic clk_main_aes;
+  logic clk_main_hmac;
+  logic clk_main_infra;
+  logic clk_fixed_infra;
+  logic clk_fixed_secure;
+  logic clk_main_secure;
+  logic clk_fixed_timers;
+  logic clk_proc_main;
+  logic clk_fixed_peri;
+  logic clk_usb_48mhz_peri;
+
+  } clkmgr_out_t;
+
+  typedef struct packed {
+    logic [2-1:0] idle;
+  } clk_hint_status_t;
+
+  parameter clk_hint_status_t CLK_HINT_STATUS_DEFAULT = '{
+    idle: {2{1'b1}}
+  };
+
+
+endpackage // clkmgr_pkg
diff --git a/hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr_reg_pkg.sv b/hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr_reg_pkg.sv
new file mode 100644
index 0000000..6983b10
--- /dev/null
+++ b/hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr_reg_pkg.sv
@@ -0,0 +1,81 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Register Package auto-generated by `reggen` containing data structure
+
+package clkmgr_reg_pkg;
+
+  // Param list
+  parameter int NumGroups = 7;
+
+  ////////////////////////////
+  // Typedefs for registers //
+  ////////////////////////////
+  typedef struct packed {
+    struct packed {
+      logic        q;
+    } clk_fixed_peri_en;
+    struct packed {
+      logic        q;
+    } clk_usb_48mhz_peri_en;
+  } clkmgr_reg2hw_clk_enables_reg_t;
+
+  typedef struct packed {
+    struct packed {
+      logic        q;
+    } clk_main_aes_hint;
+    struct packed {
+      logic        q;
+    } clk_main_hmac_hint;
+  } clkmgr_reg2hw_clk_hints_reg_t;
+
+
+  typedef struct packed {
+    struct packed {
+      logic        d;
+      logic        de;
+    } clk_main_aes_val;
+    struct packed {
+      logic        d;
+      logic        de;
+    } clk_main_hmac_val;
+  } clkmgr_hw2reg_clk_hints_status_reg_t;
+
+
+  ///////////////////////////////////////
+  // Register to internal design logic //
+  ///////////////////////////////////////
+  typedef struct packed {
+    clkmgr_reg2hw_clk_enables_reg_t clk_enables; // [3:2]
+    clkmgr_reg2hw_clk_hints_reg_t clk_hints; // [1:0]
+  } clkmgr_reg2hw_t;
+
+  ///////////////////////////////////////
+  // Internal design logic to register //
+  ///////////////////////////////////////
+  typedef struct packed {
+    clkmgr_hw2reg_clk_hints_status_reg_t clk_hints_status; // [3:4]
+  } clkmgr_hw2reg_t;
+
+  // Register Address
+  parameter logic [3:0] CLKMGR_CLK_ENABLES_OFFSET = 4'h 0;
+  parameter logic [3:0] CLKMGR_CLK_HINTS_OFFSET = 4'h 4;
+  parameter logic [3:0] CLKMGR_CLK_HINTS_STATUS_OFFSET = 4'h 8;
+
+
+  // Register Index
+  typedef enum int {
+    CLKMGR_CLK_ENABLES,
+    CLKMGR_CLK_HINTS,
+    CLKMGR_CLK_HINTS_STATUS
+  } clkmgr_id_e;
+
+  // Register width information to check illegal writes
+  parameter logic [3:0] CLKMGR_PERMIT [3] = '{
+    4'b 0001, // index[0] CLKMGR_CLK_ENABLES
+    4'b 0001, // index[1] CLKMGR_CLK_HINTS
+    4'b 0001  // index[2] CLKMGR_CLK_HINTS_STATUS
+  };
+endpackage
+
diff --git a/hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr_reg_top.sv b/hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr_reg_top.sv
new file mode 100644
index 0000000..2717958
--- /dev/null
+++ b/hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr_reg_top.sv
@@ -0,0 +1,321 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Register Top module auto-generated by `reggen`
+
+`include "prim_assert.sv"
+
+module clkmgr_reg_top (
+  input clk_i,
+  input rst_ni,
+
+  // Below Regster interface can be changed
+  input  tlul_pkg::tl_h2d_t tl_i,
+  output tlul_pkg::tl_d2h_t tl_o,
+  // To HW
+  output clkmgr_reg_pkg::clkmgr_reg2hw_t reg2hw, // Write
+  input  clkmgr_reg_pkg::clkmgr_hw2reg_t hw2reg, // Read
+
+  // Config
+  input devmode_i // If 1, explicit error return for unmapped register access
+);
+
+  import clkmgr_reg_pkg::* ;
+
+  localparam int AW = 4;
+  localparam int DW = 32;
+  localparam int DBW = DW/8;                    // Byte Width
+
+  // register signals
+  logic           reg_we;
+  logic           reg_re;
+  logic [AW-1:0]  reg_addr;
+  logic [DW-1:0]  reg_wdata;
+  logic [DBW-1:0] reg_be;
+  logic [DW-1:0]  reg_rdata;
+  logic           reg_error;
+
+  logic          addrmiss, wr_err;
+
+  logic [DW-1:0] reg_rdata_next;
+
+  tlul_pkg::tl_h2d_t tl_reg_h2d;
+  tlul_pkg::tl_d2h_t tl_reg_d2h;
+
+  assign tl_reg_h2d = tl_i;
+  assign tl_o       = tl_reg_d2h;
+
+  tlul_adapter_reg #(
+    .RegAw(AW),
+    .RegDw(DW)
+  ) u_reg_if (
+    .clk_i,
+    .rst_ni,
+
+    .tl_i (tl_reg_h2d),
+    .tl_o (tl_reg_d2h),
+
+    .we_o    (reg_we),
+    .re_o    (reg_re),
+    .addr_o  (reg_addr),
+    .wdata_o (reg_wdata),
+    .be_o    (reg_be),
+    .rdata_i (reg_rdata),
+    .error_i (reg_error)
+  );
+
+  assign reg_rdata = reg_rdata_next ;
+  assign reg_error = (devmode_i & addrmiss) | wr_err ;
+
+  // Define SW related signals
+  // Format: <reg>_<field>_{wd|we|qs}
+  //        or <reg>_{wd|we|qs} if field == 1 or 0
+  logic clk_enables_clk_fixed_peri_en_qs;
+  logic clk_enables_clk_fixed_peri_en_wd;
+  logic clk_enables_clk_fixed_peri_en_we;
+  logic clk_enables_clk_usb_48mhz_peri_en_qs;
+  logic clk_enables_clk_usb_48mhz_peri_en_wd;
+  logic clk_enables_clk_usb_48mhz_peri_en_we;
+  logic clk_hints_clk_main_aes_hint_qs;
+  logic clk_hints_clk_main_aes_hint_wd;
+  logic clk_hints_clk_main_aes_hint_we;
+  logic clk_hints_clk_main_hmac_hint_qs;
+  logic clk_hints_clk_main_hmac_hint_wd;
+  logic clk_hints_clk_main_hmac_hint_we;
+  logic clk_hints_status_clk_main_aes_val_qs;
+  logic clk_hints_status_clk_main_hmac_val_qs;
+
+  // Register instances
+  // R[clk_enables]: V(False)
+
+  //   F[clk_fixed_peri_en]: 0:0
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h1)
+  ) u_clk_enables_clk_fixed_peri_en (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (clk_enables_clk_fixed_peri_en_we),
+    .wd     (clk_enables_clk_fixed_peri_en_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.clk_enables.clk_fixed_peri_en.q ),
+
+    // to register interface (read)
+    .qs     (clk_enables_clk_fixed_peri_en_qs)
+  );
+
+
+  //   F[clk_usb_48mhz_peri_en]: 1:1
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h1)
+  ) u_clk_enables_clk_usb_48mhz_peri_en (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (clk_enables_clk_usb_48mhz_peri_en_we),
+    .wd     (clk_enables_clk_usb_48mhz_peri_en_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.clk_enables.clk_usb_48mhz_peri_en.q ),
+
+    // to register interface (read)
+    .qs     (clk_enables_clk_usb_48mhz_peri_en_qs)
+  );
+
+
+  // R[clk_hints]: V(False)
+
+  //   F[clk_main_aes_hint]: 0:0
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h1)
+  ) u_clk_hints_clk_main_aes_hint (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (clk_hints_clk_main_aes_hint_we),
+    .wd     (clk_hints_clk_main_aes_hint_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.clk_hints.clk_main_aes_hint.q ),
+
+    // to register interface (read)
+    .qs     (clk_hints_clk_main_aes_hint_qs)
+  );
+
+
+  //   F[clk_main_hmac_hint]: 1:1
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h1)
+  ) u_clk_hints_clk_main_hmac_hint (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (clk_hints_clk_main_hmac_hint_we),
+    .wd     (clk_hints_clk_main_hmac_hint_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.clk_hints.clk_main_hmac_hint.q ),
+
+    // to register interface (read)
+    .qs     (clk_hints_clk_main_hmac_hint_qs)
+  );
+
+
+  // R[clk_hints_status]: V(False)
+
+  //   F[clk_main_aes_val]: 0:0
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RO"),
+    .RESVAL  (1'h1)
+  ) u_clk_hints_status_clk_main_aes_val (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    .we     (1'b0),
+    .wd     ('0  ),
+
+    // from internal hardware
+    .de     (hw2reg.clk_hints_status.clk_main_aes_val.de),
+    .d      (hw2reg.clk_hints_status.clk_main_aes_val.d ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (),
+
+    // to register interface (read)
+    .qs     (clk_hints_status_clk_main_aes_val_qs)
+  );
+
+
+  //   F[clk_main_hmac_val]: 1:1
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RO"),
+    .RESVAL  (1'h1)
+  ) u_clk_hints_status_clk_main_hmac_val (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    .we     (1'b0),
+    .wd     ('0  ),
+
+    // from internal hardware
+    .de     (hw2reg.clk_hints_status.clk_main_hmac_val.de),
+    .d      (hw2reg.clk_hints_status.clk_main_hmac_val.d ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (),
+
+    // to register interface (read)
+    .qs     (clk_hints_status_clk_main_hmac_val_qs)
+  );
+
+
+
+
+  logic [2:0] addr_hit;
+  always_comb begin
+    addr_hit = '0;
+    addr_hit[0] = (reg_addr == CLKMGR_CLK_ENABLES_OFFSET);
+    addr_hit[1] = (reg_addr == CLKMGR_CLK_HINTS_OFFSET);
+    addr_hit[2] = (reg_addr == CLKMGR_CLK_HINTS_STATUS_OFFSET);
+  end
+
+  assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
+
+  // Check sub-word write is permitted
+  always_comb begin
+    wr_err = 1'b0;
+    if (addr_hit[0] && reg_we && (CLKMGR_PERMIT[0] != (CLKMGR_PERMIT[0] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[1] && reg_we && (CLKMGR_PERMIT[1] != (CLKMGR_PERMIT[1] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[2] && reg_we && (CLKMGR_PERMIT[2] != (CLKMGR_PERMIT[2] & reg_be))) wr_err = 1'b1 ;
+  end
+
+  assign clk_enables_clk_fixed_peri_en_we = addr_hit[0] & reg_we & ~wr_err;
+  assign clk_enables_clk_fixed_peri_en_wd = reg_wdata[0];
+
+  assign clk_enables_clk_usb_48mhz_peri_en_we = addr_hit[0] & reg_we & ~wr_err;
+  assign clk_enables_clk_usb_48mhz_peri_en_wd = reg_wdata[1];
+
+  assign clk_hints_clk_main_aes_hint_we = addr_hit[1] & reg_we & ~wr_err;
+  assign clk_hints_clk_main_aes_hint_wd = reg_wdata[0];
+
+  assign clk_hints_clk_main_hmac_hint_we = addr_hit[1] & reg_we & ~wr_err;
+  assign clk_hints_clk_main_hmac_hint_wd = reg_wdata[1];
+
+
+
+  // Read data return
+  always_comb begin
+    reg_rdata_next = '0;
+    unique case (1'b1)
+      addr_hit[0]: begin
+        reg_rdata_next[0] = clk_enables_clk_fixed_peri_en_qs;
+        reg_rdata_next[1] = clk_enables_clk_usb_48mhz_peri_en_qs;
+      end
+
+      addr_hit[1]: begin
+        reg_rdata_next[0] = clk_hints_clk_main_aes_hint_qs;
+        reg_rdata_next[1] = clk_hints_clk_main_hmac_hint_qs;
+      end
+
+      addr_hit[2]: begin
+        reg_rdata_next[0] = clk_hints_status_clk_main_aes_val_qs;
+        reg_rdata_next[1] = clk_hints_status_clk_main_hmac_val_qs;
+      end
+
+      default: begin
+        reg_rdata_next = '1;
+      end
+    endcase
+  end
+
+  // Assertions for Register Interface
+  `ASSERT_PULSE(wePulse, reg_we)
+  `ASSERT_PULSE(rePulse, reg_re)
+
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+
+  // this is formulated as an assumption such that the FPV testbenches do disprove this
+  // property by mistake
+  `ASSUME(reqParity, tl_reg_h2d.a_valid |-> tl_reg_h2d.a_user.parity_en == 1'b0)
+
+endmodule
diff --git a/hw/top_earlgrey/ip/xbar_main/data/autogen/xbar_main.gen.hjson b/hw/top_earlgrey/ip/xbar_main/data/autogen/xbar_main.gen.hjson
index 9f6b189..3b7c4f7 100644
--- a/hw/top_earlgrey/ip/xbar_main/data/autogen/xbar_main.gen.hjson
+++ b/hw/top_earlgrey/ip/xbar_main/data/autogen/xbar_main.gen.hjson
@@ -22,8 +22,8 @@
   }
   clock_connections:
   {
-    clk_main_i: clk_main_infra
-    clk_fixed_i: clk_fixed_infra
+    clk_main_i: clkmgr_clocks.clk_main_infra
+    clk_fixed_i: clkmgr_clocks.clk_fixed_infra
   }
   connections:
   {
@@ -184,7 +184,7 @@
         }
         {
           base_addr: 0x400A0000
-          size_byte: 0x20000
+          size_byte: 0x21000
         }
         {
           base_addr: 0x40150000
diff --git a/hw/top_earlgrey/ip/xbar_main/dv/autogen/xbar_env_pkg__params.sv b/hw/top_earlgrey/ip/xbar_main/dv/autogen/xbar_env_pkg__params.sv
index 4b7b733..922701c 100644
--- a/hw/top_earlgrey/ip/xbar_main/dv/autogen/xbar_env_pkg__params.sv
+++ b/hw/top_earlgrey/ip/xbar_main/dv/autogen/xbar_env_pkg__params.sv
@@ -22,7 +22,7 @@
     '{"peri", '{
         '{32'h40000000, 32'h40020fff},
         '{32'h40080000, 32'h40080fff},
-        '{32'h400a0000, 32'h400bffff},
+        '{32'h400a0000, 32'h400c0fff},
         '{32'h40150000, 32'h40150fff}
     }},
     '{"flash_ctrl", '{
diff --git a/hw/top_earlgrey/ip/xbar_main/rtl/autogen/tl_main_pkg.sv b/hw/top_earlgrey/ip/xbar_main/rtl/autogen/tl_main_pkg.sv
index 934b35b..049b428 100644
--- a/hw/top_earlgrey/ip/xbar_main/rtl/autogen/tl_main_pkg.sv
+++ b/hw/top_earlgrey/ip/xbar_main/rtl/autogen/tl_main_pkg.sv
@@ -31,7 +31,7 @@
   localparam logic [3:0][31:0] ADDR_MASK_PERI          = {
     32'h 00020fff,
     32'h 00000fff,
-    32'h 0001ffff,
+    32'h 00020fff,
     32'h 00000fff
   };
   localparam logic [31:0] ADDR_MASK_FLASH_CTRL    = 32'h 00000fff;
diff --git a/hw/top_earlgrey/ip/xbar_peri/data/autogen/xbar_peri.gen.hjson b/hw/top_earlgrey/ip/xbar_peri/data/autogen/xbar_peri.gen.hjson
index d4bffa1..781835f 100644
--- a/hw/top_earlgrey/ip/xbar_peri/data/autogen/xbar_peri.gen.hjson
+++ b/hw/top_earlgrey/ip/xbar_peri/data/autogen/xbar_peri.gen.hjson
@@ -20,7 +20,7 @@
   }
   clock_connections:
   {
-    clk_peri_i: clk_fixed_infra
+    clk_peri_i: clkmgr_clocks.clk_fixed_infra
   }
   connections:
   {
@@ -33,6 +33,7 @@
       usbdev
       pwrmgr
       rstmgr
+      clkmgr
     ]
   }
   nodes:
@@ -166,6 +167,23 @@
       xbar: false
       pipeline_byp: "true"
     }
+    {
+      name: clkmgr
+      type: device
+      clock: clk_peri_i
+      reset: rst_peri_ni
+      pipeline: "false"
+      inst_type: clkmgr
+      addr_range:
+      [
+        {
+          base_addr: 0x400C0000
+          size_byte: 0x1000
+        }
+      ]
+      xbar: false
+      pipeline_byp: "true"
+    }
   ]
   clock: clk_peri_i
   type: xbar
diff --git a/hw/top_earlgrey/ip/xbar_peri/dv/autogen/tb__xbar_connect.sv b/hw/top_earlgrey/ip/xbar_peri/dv/autogen/tb__xbar_connect.sv
index 6788161..51947d7 100644
--- a/hw/top_earlgrey/ip/xbar_peri/dv/autogen/tb__xbar_connect.sv
+++ b/hw/top_earlgrey/ip/xbar_peri/dv/autogen/tb__xbar_connect.sv
@@ -22,3 +22,4 @@
 `CONNECT_TL_DEVICE_IF(usbdev)
 `CONNECT_TL_DEVICE_IF(pwrmgr)
 `CONNECT_TL_DEVICE_IF(rstmgr)
+`CONNECT_TL_DEVICE_IF(clkmgr)
diff --git a/hw/top_earlgrey/ip/xbar_peri/dv/autogen/xbar_env_pkg__params.sv b/hw/top_earlgrey/ip/xbar_peri/dv/autogen/xbar_env_pkg__params.sv
index c87c7a0..f4b264c 100644
--- a/hw/top_earlgrey/ip/xbar_peri/dv/autogen/xbar_env_pkg__params.sv
+++ b/hw/top_earlgrey/ip/xbar_peri/dv/autogen/xbar_env_pkg__params.sv
@@ -27,6 +27,9 @@
     }},
     '{"rstmgr", '{
         '{32'h400b0000, 32'h400b0fff}
+    }},
+    '{"clkmgr", '{
+        '{32'h400c0000, 32'h400c0fff}
 }}};
 
   // List of Xbar hosts
@@ -38,5 +41,6 @@
         "rv_timer",
         "usbdev",
         "pwrmgr",
-        "rstmgr"}}
+        "rstmgr",
+        "clkmgr"}}
 };
diff --git a/hw/top_earlgrey/ip/xbar_peri/dv/autogen/xbar_peri_bind.sv b/hw/top_earlgrey/ip/xbar_peri/dv/autogen/xbar_peri_bind.sv
index 79f7ba0..501dddc 100644
--- a/hw/top_earlgrey/ip/xbar_peri/dv/autogen/xbar_peri_bind.sv
+++ b/hw/top_earlgrey/ip/xbar_peri/dv/autogen/xbar_peri_bind.sv
@@ -56,5 +56,11 @@
     .h2d    (tl_rstmgr_o),
     .d2h    (tl_rstmgr_i)
   );
+  bind xbar_peri tlul_assert #(.EndpointType("Host")) tlul_assert_device_clkmgr (
+    .clk_i  (clk_peri_i),
+    .rst_ni (rst_peri_ni),
+    .h2d    (tl_clkmgr_o),
+    .d2h    (tl_clkmgr_i)
+  );
 
 endmodule
diff --git a/hw/top_earlgrey/ip/xbar_peri/rtl/autogen/tl_peri_pkg.sv b/hw/top_earlgrey/ip/xbar_peri/rtl/autogen/tl_peri_pkg.sv
index d8d3e2e..6b86f90 100644
--- a/hw/top_earlgrey/ip/xbar_peri/rtl/autogen/tl_peri_pkg.sv
+++ b/hw/top_earlgrey/ip/xbar_peri/rtl/autogen/tl_peri_pkg.sv
@@ -13,6 +13,7 @@
   localparam logic [31:0] ADDR_SPACE_USBDEV     = 32'h 40150000;
   localparam logic [31:0] ADDR_SPACE_PWRMGR     = 32'h 400a0000;
   localparam logic [31:0] ADDR_SPACE_RSTMGR     = 32'h 400b0000;
+  localparam logic [31:0] ADDR_SPACE_CLKMGR     = 32'h 400c0000;
 
   localparam logic [31:0] ADDR_MASK_UART       = 32'h 00000fff;
   localparam logic [31:0] ADDR_MASK_GPIO       = 32'h 00000fff;
@@ -21,9 +22,10 @@
   localparam logic [31:0] ADDR_MASK_USBDEV     = 32'h 00000fff;
   localparam logic [31:0] ADDR_MASK_PWRMGR     = 32'h 00000fff;
   localparam logic [31:0] ADDR_MASK_RSTMGR     = 32'h 00000fff;
+  localparam logic [31:0] ADDR_MASK_CLKMGR     = 32'h 00000fff;
 
   localparam int N_HOST   = 1;
-  localparam int N_DEVICE = 7;
+  localparam int N_DEVICE = 8;
 
   typedef enum int {
     TlUart = 0,
@@ -32,7 +34,8 @@
     TlRvTimer = 3,
     TlUsbdev = 4,
     TlPwrmgr = 5,
-    TlRstmgr = 6
+    TlRstmgr = 6,
+    TlClkmgr = 7
   } tl_device_e;
 
   typedef enum int {
diff --git a/hw/top_earlgrey/ip/xbar_peri/rtl/autogen/xbar_peri.sv b/hw/top_earlgrey/ip/xbar_peri/rtl/autogen/xbar_peri.sv
index bcff74a..bff04d4 100644
--- a/hw/top_earlgrey/ip/xbar_peri/rtl/autogen/xbar_peri.sv
+++ b/hw/top_earlgrey/ip/xbar_peri/rtl/autogen/xbar_peri.sv
@@ -7,7 +7,7 @@
 //
 // Interconnect
 // main
-//   -> s1n_8
+//   -> s1n_9
 //     -> uart
 //     -> gpio
 //     -> spi_device
@@ -15,6 +15,7 @@
 //     -> usbdev
 //     -> pwrmgr
 //     -> rstmgr
+//     -> clkmgr
 
 module xbar_peri (
   input clk_peri_i,
@@ -39,6 +40,8 @@
   input  tlul_pkg::tl_d2h_t tl_pwrmgr_i,
   output tlul_pkg::tl_h2d_t tl_rstmgr_o,
   input  tlul_pkg::tl_d2h_t tl_rstmgr_i,
+  output tlul_pkg::tl_h2d_t tl_clkmgr_o,
+  input  tlul_pkg::tl_d2h_t tl_clkmgr_i,
 
   input scanmode_i
 );
@@ -51,65 +54,71 @@
   logic unused_scanmode;
   assign unused_scanmode = scanmode_i;
 
-  tl_h2d_t tl_s1n_8_us_h2d ;
-  tl_d2h_t tl_s1n_8_us_d2h ;
+  tl_h2d_t tl_s1n_9_us_h2d ;
+  tl_d2h_t tl_s1n_9_us_d2h ;
 
 
-  tl_h2d_t tl_s1n_8_ds_h2d [7];
-  tl_d2h_t tl_s1n_8_ds_d2h [7];
+  tl_h2d_t tl_s1n_9_ds_h2d [8];
+  tl_d2h_t tl_s1n_9_ds_d2h [8];
 
   // Create steering signal
-  logic [2:0] dev_sel_s1n_8;
+  logic [3:0] dev_sel_s1n_9;
 
 
 
-  assign tl_uart_o = tl_s1n_8_ds_h2d[0];
-  assign tl_s1n_8_ds_d2h[0] = tl_uart_i;
+  assign tl_uart_o = tl_s1n_9_ds_h2d[0];
+  assign tl_s1n_9_ds_d2h[0] = tl_uart_i;
 
-  assign tl_gpio_o = tl_s1n_8_ds_h2d[1];
-  assign tl_s1n_8_ds_d2h[1] = tl_gpio_i;
+  assign tl_gpio_o = tl_s1n_9_ds_h2d[1];
+  assign tl_s1n_9_ds_d2h[1] = tl_gpio_i;
 
-  assign tl_spi_device_o = tl_s1n_8_ds_h2d[2];
-  assign tl_s1n_8_ds_d2h[2] = tl_spi_device_i;
+  assign tl_spi_device_o = tl_s1n_9_ds_h2d[2];
+  assign tl_s1n_9_ds_d2h[2] = tl_spi_device_i;
 
-  assign tl_rv_timer_o = tl_s1n_8_ds_h2d[3];
-  assign tl_s1n_8_ds_d2h[3] = tl_rv_timer_i;
+  assign tl_rv_timer_o = tl_s1n_9_ds_h2d[3];
+  assign tl_s1n_9_ds_d2h[3] = tl_rv_timer_i;
 
-  assign tl_usbdev_o = tl_s1n_8_ds_h2d[4];
-  assign tl_s1n_8_ds_d2h[4] = tl_usbdev_i;
+  assign tl_usbdev_o = tl_s1n_9_ds_h2d[4];
+  assign tl_s1n_9_ds_d2h[4] = tl_usbdev_i;
 
-  assign tl_pwrmgr_o = tl_s1n_8_ds_h2d[5];
-  assign tl_s1n_8_ds_d2h[5] = tl_pwrmgr_i;
+  assign tl_pwrmgr_o = tl_s1n_9_ds_h2d[5];
+  assign tl_s1n_9_ds_d2h[5] = tl_pwrmgr_i;
 
-  assign tl_rstmgr_o = tl_s1n_8_ds_h2d[6];
-  assign tl_s1n_8_ds_d2h[6] = tl_rstmgr_i;
+  assign tl_rstmgr_o = tl_s1n_9_ds_h2d[6];
+  assign tl_s1n_9_ds_d2h[6] = tl_rstmgr_i;
 
-  assign tl_s1n_8_us_h2d = tl_main_i;
-  assign tl_main_o = tl_s1n_8_us_d2h;
+  assign tl_clkmgr_o = tl_s1n_9_ds_h2d[7];
+  assign tl_s1n_9_ds_d2h[7] = tl_clkmgr_i;
+
+  assign tl_s1n_9_us_h2d = tl_main_i;
+  assign tl_main_o = tl_s1n_9_us_d2h;
 
   always_comb begin
     // default steering to generate error response if address is not within the range
-    dev_sel_s1n_8 = 3'd7;
-    if ((tl_s1n_8_us_h2d.a_address & ~(ADDR_MASK_UART)) == ADDR_SPACE_UART) begin
-      dev_sel_s1n_8 = 3'd0;
+    dev_sel_s1n_9 = 4'd8;
+    if ((tl_s1n_9_us_h2d.a_address & ~(ADDR_MASK_UART)) == ADDR_SPACE_UART) begin
+      dev_sel_s1n_9 = 4'd0;
 
-    end else if ((tl_s1n_8_us_h2d.a_address & ~(ADDR_MASK_GPIO)) == ADDR_SPACE_GPIO) begin
-      dev_sel_s1n_8 = 3'd1;
+    end else if ((tl_s1n_9_us_h2d.a_address & ~(ADDR_MASK_GPIO)) == ADDR_SPACE_GPIO) begin
+      dev_sel_s1n_9 = 4'd1;
 
-    end else if ((tl_s1n_8_us_h2d.a_address & ~(ADDR_MASK_SPI_DEVICE)) == ADDR_SPACE_SPI_DEVICE) begin
-      dev_sel_s1n_8 = 3'd2;
+    end else if ((tl_s1n_9_us_h2d.a_address & ~(ADDR_MASK_SPI_DEVICE)) == ADDR_SPACE_SPI_DEVICE) begin
+      dev_sel_s1n_9 = 4'd2;
 
-    end else if ((tl_s1n_8_us_h2d.a_address & ~(ADDR_MASK_RV_TIMER)) == ADDR_SPACE_RV_TIMER) begin
-      dev_sel_s1n_8 = 3'd3;
+    end else if ((tl_s1n_9_us_h2d.a_address & ~(ADDR_MASK_RV_TIMER)) == ADDR_SPACE_RV_TIMER) begin
+      dev_sel_s1n_9 = 4'd3;
 
-    end else if ((tl_s1n_8_us_h2d.a_address & ~(ADDR_MASK_USBDEV)) == ADDR_SPACE_USBDEV) begin
-      dev_sel_s1n_8 = 3'd4;
+    end else if ((tl_s1n_9_us_h2d.a_address & ~(ADDR_MASK_USBDEV)) == ADDR_SPACE_USBDEV) begin
+      dev_sel_s1n_9 = 4'd4;
 
-    end else if ((tl_s1n_8_us_h2d.a_address & ~(ADDR_MASK_PWRMGR)) == ADDR_SPACE_PWRMGR) begin
-      dev_sel_s1n_8 = 3'd5;
+    end else if ((tl_s1n_9_us_h2d.a_address & ~(ADDR_MASK_PWRMGR)) == ADDR_SPACE_PWRMGR) begin
+      dev_sel_s1n_9 = 4'd5;
 
-    end else if ((tl_s1n_8_us_h2d.a_address & ~(ADDR_MASK_RSTMGR)) == ADDR_SPACE_RSTMGR) begin
-      dev_sel_s1n_8 = 3'd6;
+    end else if ((tl_s1n_9_us_h2d.a_address & ~(ADDR_MASK_RSTMGR)) == ADDR_SPACE_RSTMGR) begin
+      dev_sel_s1n_9 = 4'd6;
+
+    end else if ((tl_s1n_9_us_h2d.a_address & ~(ADDR_MASK_CLKMGR)) == ADDR_SPACE_CLKMGR) begin
+      dev_sel_s1n_9 = 4'd7;
 end
   end
 
@@ -118,17 +127,17 @@
   tlul_socket_1n #(
     .HReqDepth (4'h0),
     .HRspDepth (4'h0),
-    .DReqDepth ({7{4'h0}}),
-    .DRspDepth ({7{4'h0}}),
-    .N         (7)
-  ) u_s1n_8 (
+    .DReqDepth ({8{4'h0}}),
+    .DRspDepth ({8{4'h0}}),
+    .N         (8)
+  ) u_s1n_9 (
     .clk_i        (clk_peri_i),
     .rst_ni       (rst_peri_ni),
-    .tl_h_i       (tl_s1n_8_us_h2d),
-    .tl_h_o       (tl_s1n_8_us_d2h),
-    .tl_d_o       (tl_s1n_8_ds_h2d),
-    .tl_d_i       (tl_s1n_8_ds_d2h),
-    .dev_select   (dev_sel_s1n_8)
+    .tl_h_i       (tl_s1n_9_us_h2d),
+    .tl_h_o       (tl_s1n_9_us_d2h),
+    .tl_d_o       (tl_s1n_9_ds_h2d),
+    .tl_d_i       (tl_s1n_9_ds_d2h),
+    .dev_select   (dev_sel_s1n_9)
   );
 
 endmodule
diff --git a/hw/top_earlgrey/rtl/autogen/top_earlgrey.sv b/hw/top_earlgrey/rtl/autogen/top_earlgrey.sv
index 8f65038..44a9332 100644
--- a/hw/top_earlgrey/rtl/autogen/top_earlgrey.sv
+++ b/hw/top_earlgrey/rtl/autogen/top_earlgrey.sv
@@ -86,6 +86,8 @@
   tl_d2h_t  tl_pwrmgr_d_d2h;
   tl_h2d_t  tl_rstmgr_d_h2d;
   tl_d2h_t  tl_rstmgr_d_d2h;
+  tl_h2d_t  tl_clkmgr_d_h2d;
+  tl_d2h_t  tl_clkmgr_d_d2h;
   tl_h2d_t  tl_nmi_gen_d_h2d;
   tl_d2h_t  tl_nmi_gen_d_d2h;
   tl_h2d_t  tl_usbdev_d_h2d;
@@ -106,21 +108,6 @@
   assign tl_main_h_h2d = tl_peri_d_h2d;
   assign tl_peri_d_d2h = tl_main_h_d2h;
 
-  //clock wires declaration
-  logic clk_fixed_powerup;
-  logic clk_main_powerup;
-  logic clk_usb_48mhz_powerup;
-  logic clk_main_aes;
-  logic clk_main_hmac;
-  logic clk_main_infra;
-  logic clk_fixed_infra;
-  logic clk_fixed_secure;
-  logic clk_main_secure;
-  logic clk_fixed_peri;
-  logic clk_usb_48mhz_peri;
-  logic clk_fixed_timers;
-  logic clk_proc_main;
-
   // Signals
   logic [31:0] mio2periph;
   logic [31:0] periph2mio;
@@ -151,6 +138,7 @@
   // alert_handler
   // pwrmgr
   // rstmgr
+  // clkmgr
   // nmi_gen
   // usbdev
   logic        cio_usbdev_sense_p2d;
@@ -249,25 +237,12 @@
   flash_ctrl_pkg::flash_rsp_t       flash_ctrl_flash_rsp;
   pwrmgr_pkg::pwr_rst_req_t       pwrmgr_pwr_rst_req;
   pwrmgr_pkg::pwr_rst_rsp_t       pwrmgr_pwr_rst_rsp;
+  pwrmgr_pkg::pwr_clk_req_t       pwrmgr_pwr_clk_req;
+  pwrmgr_pkg::pwr_clk_rsp_t       pwrmgr_pwr_clk_rsp;
   rstmgr_pkg::rstmgr_out_t       rstmgr_resets;
   rstmgr_pkg::rstmgr_cpu_t       rstmgr_cpu;
   pwrmgr_pkg::pwr_cpu_t       pwrmgr_pwr_cpu;
-
-  // Clock assignments
-  // These assignments are temporary until the creation of the clock controller
-  assign clk_fixed_powerup = clk_fixed_i;
-  assign clk_main_powerup = clk_i;
-  assign clk_usb_48mhz_powerup = clk_usb_48mhz_i;
-  assign clk_main_aes = clk_i;
-  assign clk_main_hmac = clk_i;
-  assign clk_main_infra = clk_i;
-  assign clk_fixed_infra = clk_fixed_i;
-  assign clk_fixed_secure = clk_fixed_i;
-  assign clk_main_secure = clk_i;
-  assign clk_fixed_peri = clk_fixed_i;
-  assign clk_usb_48mhz_peri = clk_usb_48mhz_i;
-  assign clk_fixed_timers = clk_fixed_i;
-  assign clk_proc_main = clk_i;
+  clkmgr_pkg::clkmgr_out_t       clkmgr_clocks;
 
   // Non-debug module reset == reset for everything except for the debug module
   logic ndmreset_req;
@@ -293,7 +268,7 @@
     .PipeLine                 (IbexPipeLine)
   ) u_rv_core_ibex (
     // clock and reset
-    .clk_i                (clk_proc_main),
+    .clk_i                (clkmgr_clocks.clk_proc_main),
     .rst_ni               (rstmgr_resets.rst_sys_n),
     .test_en_i            (1'b0),
     // static pinning
@@ -324,7 +299,7 @@
     .NrHarts     (1),
     .IdcodeValue (JTAG_IDCODE)
   ) u_dm_top (
-    .clk_i         (clk_proc_main),
+    .clk_i         (clkmgr_clocks.clk_proc_main),
     .rst_ni        (rstmgr_resets.rst_lc_n),
     .testmode_i    (1'b0),
     .ndmreset_o    (ndmreset_req),
@@ -364,7 +339,7 @@
     .Outstanding(2),
     .ErrOnWrite(1)
   ) u_tl_adapter_rom (
-    .clk_i   (clk_main_infra),
+    .clk_i   (clkmgr_clocks.clk_main_infra),
     .rst_ni   (rstmgr_resets.rst_sys_n),
 
     .tl_i     (tl_rom_d_h2d),
@@ -385,7 +360,7 @@
     .Width(32),
     .Depth(4096)
   ) u_rom_rom (
-    .clk_i   (clk_main_infra),
+    .clk_i   (clkmgr_clocks.clk_main_infra),
     .rst_ni   (rstmgr_resets.rst_sys_n),
     .cs_i     (rom_req),
     .addr_i   (rom_addr),
@@ -407,7 +382,7 @@
     .SramDw(32),
     .Outstanding(2)
   ) u_tl_adapter_ram_main (
-    .clk_i   (clk_main_infra),
+    .clk_i   (clkmgr_clocks.clk_main_infra),
     .rst_ni   (rstmgr_resets.rst_sys_n),
     .tl_i     (tl_ram_main_d_h2d),
     .tl_o     (tl_ram_main_d_d2h),
@@ -428,7 +403,7 @@
     .Depth(16384),
     .DataBitsPerMask(8)
   ) u_ram1p_ram_main (
-    .clk_i   (clk_main_infra),
+    .clk_i   (clkmgr_clocks.clk_main_infra),
     .rst_ni   (rstmgr_resets.rst_sys_n),
 
     .req_i    (ram_main_req),
@@ -454,7 +429,7 @@
     .ByteAccess(0),
     .ErrOnWrite(1)
   ) u_tl_adapter_eflash (
-    .clk_i   (clk_main_infra),
+    .clk_i   (clkmgr_clocks.clk_main_infra),
     .rst_ni   (rstmgr_resets.rst_lc_n),
 
     .tl_i       (tl_eflash_d_h2d),
@@ -472,7 +447,7 @@
   );
 
   flash_phy u_flash_eflash (
-    .clk_i   (clk_main_infra),
+    .clk_i   (clkmgr_clocks.clk_main_infra),
     .rst_ni   (rstmgr_resets.rst_lc_n),
     .host_req_i      (flash_host_req),
     .host_addr_i     (flash_host_addr),
@@ -506,7 +481,7 @@
       .intr_rx_timeout_o    (intr_uart_rx_timeout),
       .intr_rx_parity_err_o (intr_uart_rx_parity_err),
 
-      .clk_i (clk_fixed_secure),
+      .clk_i (clkmgr_clocks.clk_fixed_secure),
       .rst_ni (rstmgr_resets.rst_sys_fixed_n)
   );
 
@@ -524,7 +499,7 @@
       // Interrupt
       .intr_gpio_o (intr_gpio_gpio),
 
-      .clk_i (clk_fixed_peri),
+      .clk_i (clkmgr_clocks.clk_fixed_peri),
       .rst_ni (rstmgr_resets.rst_sys_fixed_n)
   );
 
@@ -550,7 +525,7 @@
       .intr_txunderflow_o (intr_spi_device_txunderflow),
       .scanmode_i   (scanmode_i),
 
-      .clk_i (clk_fixed_peri),
+      .clk_i (clkmgr_clocks.clk_fixed_peri),
       .rst_ni (rstmgr_resets.rst_spi_device_n)
   );
 
@@ -570,7 +545,7 @@
       .flash_o(flash_ctrl_flash_req),
       .flash_i(flash_ctrl_flash_rsp),
 
-      .clk_i (clk_main_infra),
+      .clk_i (clkmgr_clocks.clk_main_infra),
       .rst_ni (rstmgr_resets.rst_lc_n)
   );
 
@@ -581,7 +556,7 @@
       // Interrupt
       .intr_timer_expired_0_0_o (intr_rv_timer_timer_expired_0_0),
 
-      .clk_i (clk_fixed_timers),
+      .clk_i (clkmgr_clocks.clk_fixed_timers),
       .rst_ni (rstmgr_resets.rst_sys_fixed_n)
   );
 
@@ -589,7 +564,7 @@
       .tl_i (tl_aes_d_h2d),
       .tl_o (tl_aes_d_d2h),
 
-      .clk_i (clk_main_aes),
+      .clk_i (clkmgr_clocks.clk_main_aes),
       .rst_ni (rstmgr_resets.rst_sys_n)
   );
 
@@ -606,7 +581,7 @@
       .alert_tx_o  ( alert_tx[0:0] ),
       .alert_rx_i  ( alert_rx[0:0] ),
 
-      .clk_i (clk_main_hmac),
+      .clk_i (clkmgr_clocks.clk_main_hmac),
       .rst_ni (rstmgr_resets.rst_sys_n)
   );
 
@@ -619,7 +594,7 @@
       .irq_id_o   (irq_id),
       .msip_o     (msip),
 
-      .clk_i (clk_main_secure),
+      .clk_i (clkmgr_clocks.clk_main_secure),
       .rst_ni (rstmgr_resets.rst_sys_n)
   );
 
@@ -649,8 +624,8 @@
       .dio_oe_o,
       .dio_in_i,
 
-      .clk_i (clk_main_secure),
-      .clk_aon_i (clk_fixed_secure),
+      .clk_i (clkmgr_clocks.clk_main_secure),
+      .clk_aon_i (clkmgr_clocks.clk_fixed_secure),
       .rst_ni (rstmgr_resets.rst_sys_n),
       .rst_aon_ni (rstmgr_resets.rst_sys_fixed_n)
   );
@@ -675,7 +650,7 @@
       .esc_rx_i    ( esc_rx   ),
       .esc_tx_o    ( esc_tx   ),
 
-      .clk_i (clk_main_secure),
+      .clk_i (clkmgr_clocks.clk_main_secure),
       .rst_ni (rstmgr_resets.rst_sys_n)
   );
 
@@ -691,7 +666,8 @@
       .pwr_ast_i(pwrmgr_pkg::PWR_AST_RSP_DEFAULT),
       .pwr_rst_o(pwrmgr_pwr_rst_req),
       .pwr_rst_i(pwrmgr_pwr_rst_rsp),
-      .pwr_clk_o(),
+      .pwr_clk_o(pwrmgr_pwr_clk_req),
+      .pwr_clk_i(pwrmgr_pwr_clk_rsp),
       .pwr_otp_o(),
       .pwr_otp_i(pwrmgr_pkg::PWR_OTP_RSP_DEFAULT),
       .pwr_lc_o(),
@@ -700,8 +676,8 @@
       .pwr_cpu_i(pwrmgr_pwr_cpu),
       .pwr_peri_i(pwrmgr_pkg::PWR_PERI_DEFAULT),
 
-      .clk_i (clk_fixed_powerup),
-      .clk_slow_i (clk_fixed_powerup),
+      .clk_i (clk_fixed_i),
+      .clk_slow_i (clk_fixed_i),
       .rst_ni (rstmgr_resets.rst_por_n),
       .rst_slow_ni (rstmgr_resets.rst_por_n)
   );
@@ -718,13 +694,34 @@
       .cpu_i(rstmgr_cpu),
       .peri_i(rstmgr_pkg::RSTMGR_PERI_DEFAULT),
 
-      .clk_i (clk_fixed_powerup),
-      .clk_main_i (clk_main_powerup),
-      .clk_fixed_i (clk_fixed_powerup),
-      .clk_usb_i (clk_usb_48mhz_powerup),
+      .clk_i (clk_fixed_i),
+      .clk_main_i (clk_i),
+      .clk_fixed_i (clk_fixed_i),
+      .clk_usb_i (clk_usb_48mhz_i),
       .rst_ni (rst_ni)
   );
 
+  clkmgr u_clkmgr (
+      .tl_i (tl_clkmgr_d_h2d),
+      .tl_o (tl_clkmgr_d_d2h),
+
+      // Inter-module signals
+      .clocks_o(clkmgr_clocks),
+      .pwr_i(pwrmgr_pwr_clk_req),
+      .pwr_o(pwrmgr_pwr_clk_rsp),
+      .dft_i(clkmgr_pkg::CLK_DFT_DEFAULT),
+      .status_i(clkmgr_pkg::CLK_HINT_STATUS_DEFAULT),
+
+      .clk_i (clk_fixed_i),
+      .clk_main_i (clk_i),
+      .clk_fixed_i (clk_fixed_i),
+      .clk_usb_48mhz_i (clk_usb_48mhz_i),
+      .rst_ni (rstmgr_resets.rst_por_n),
+      .rst_main_ni (rstmgr_resets.rst_por_n),
+      .rst_fixed_ni (rstmgr_resets.rst_por_n),
+      .rst_usb_48mhz_ni (rstmgr_resets.rst_por_n)
+  );
+
   nmi_gen u_nmi_gen (
       .tl_i (tl_nmi_gen_d_h2d),
       .tl_o (tl_nmi_gen_d_d2h),
@@ -738,7 +735,7 @@
       .esc_rx_o    ( esc_rx   ),
       .esc_tx_i    ( esc_tx   ),
 
-      .clk_i (clk_main_secure),
+      .clk_i (clkmgr_clocks.clk_main_secure),
       .rst_ni (rstmgr_resets.rst_sys_n)
   );
 
@@ -786,8 +783,8 @@
       .intr_frame_o           (intr_usbdev_frame),
       .intr_connected_o       (intr_usbdev_connected),
 
-      .clk_i (clk_fixed_peri),
-      .clk_usb_48mhz_i (clk_usb_48mhz_peri),
+      .clk_i (clkmgr_clocks.clk_fixed_peri),
+      .clk_usb_48mhz_i (clkmgr_clocks.clk_usb_48mhz_peri),
       .rst_ni (rstmgr_resets.rst_sys_fixed_n),
       .rst_usb_48mhz_ni (rstmgr_resets.rst_usb_n)
   );
@@ -848,8 +845,8 @@
 
   // TL-UL Crossbar
   xbar_main u_xbar_main (
-    .clk_main_i (clk_main_infra),
-    .clk_fixed_i (clk_fixed_infra),
+    .clk_main_i (clkmgr_clocks.clk_main_infra),
+    .clk_fixed_i (clkmgr_clocks.clk_fixed_infra),
     .rst_main_ni (rstmgr_resets.rst_sys_n),
     .rst_fixed_ni (rstmgr_resets.rst_sys_fixed_n),
     .tl_corei_i         (tl_corei_h_h2d),
@@ -886,7 +883,7 @@
     .scanmode_i
   );
   xbar_peri u_xbar_peri (
-    .clk_peri_i (clk_fixed_infra),
+    .clk_peri_i (clkmgr_clocks.clk_fixed_infra),
     .rst_peri_ni (rstmgr_resets.rst_sys_fixed_n),
     .tl_main_i       (tl_main_h_h2d),
     .tl_main_o       (tl_main_h_d2h),
@@ -904,6 +901,8 @@
     .tl_pwrmgr_i     (tl_pwrmgr_d_d2h),
     .tl_rstmgr_o     (tl_rstmgr_d_h2d),
     .tl_rstmgr_i     (tl_rstmgr_d_d2h),
+    .tl_clkmgr_o     (tl_clkmgr_d_h2d),
+    .tl_clkmgr_i     (tl_clkmgr_d_d2h),
 
     .scanmode_i
   );
diff --git a/hw/top_earlgrey/sw/autogen/top_earlgrey.h b/hw/top_earlgrey/sw/autogen/top_earlgrey.h
index 240d176..3789f0e 100644
--- a/hw/top_earlgrey/sw/autogen/top_earlgrey.h
+++ b/hw/top_earlgrey/sw/autogen/top_earlgrey.h
@@ -183,6 +183,14 @@
 #define TOP_EARLGREY_RSTMGR_BASE_ADDR 0x400B0000u
 
 /**
+ * Base address for clkmgr peripheral in top earlgrey.
+ *
+ * This should be used with #mmio_region_from_addr to access the memory-mapped
+ * registers associated with the peripheral (usually via a DIF).
+ */
+#define TOP_EARLGREY_CLKMGR_BASE_ADDR 0x400C0000u
+
+/**
  * Base address for nmi_gen peripheral in top earlgrey.
  *
  * This should be used with #mmio_region_from_addr to access the memory-mapped
diff --git a/hw/top_earlgrey/top_earlgrey.core b/hw/top_earlgrey/top_earlgrey.core
index cbe9e08..4ca068a 100644
--- a/hw/top_earlgrey/top_earlgrey.core
+++ b/hw/top_earlgrey/top_earlgrey.core
@@ -9,6 +9,7 @@
     depend:
       - lowrisc:ip:uart:0.1
       - lowrisc:top_earlgrey:alert_handler_reg
+      - lowrisc:top_earlgrey:clkmgr
       - lowrisc:ip:alert_handler_component
       - lowrisc:ip:gpio
       - lowrisc:ip:rv_core_ibex
diff --git a/util/topgen.py b/util/topgen.py
index b86ee90..04b0e8d 100755
--- a/util/topgen.py
+++ b/util/topgen.py
@@ -18,10 +18,7 @@
 
 import tlgen
 from reggen import gen_dv, gen_rtl, gen_fpv, validate
-from topgen import get_hjsonobj_xbars, merge_top, search_ips, validate_top
-
-# Filter from IP list but adding generated hjson
-filter_list = ['rv_plic', 'pinmux', 'alert_handler']
+from topgen import get_hjsonobj_xbars, merge_top, search_ips, validate_top, amend_clocks
 
 # Common header for generated files
 genhdr = '''// Copyright lowRISC contributors.
@@ -423,6 +420,78 @@
     validate.validate(hjson_obj)
     gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
 
+def generate_clkmgr(top, cfg_path, out_path):
+
+    # Target paths
+    rtl_path = out_path / 'ip/clkmgr/rtl/autogen'
+    rtl_path.mkdir(parents=True, exist_ok=True)
+    data_path = out_path / 'ip/clkmgr/data/autogen'
+    data_path.mkdir(parents=True, exist_ok=True)
+
+    # Template paths
+    hjson_tpl = cfg_path / '../ip/clkmgr/data/clkmgr.hjson.tpl'
+    rtl_tpl   = cfg_path / '../ip/clkmgr/data/clkmgr.sv.tpl'
+    pkg_tpl   = cfg_path / '../ip/clkmgr/data/clkmgr_pkg.sv.tpl'
+
+    hjson_out = data_path / 'clkmgr.hjson'
+    rtl_out   = rtl_path / 'clkmgr.sv'
+    pkg_out   = rtl_path / 'clkmgr_pkg.sv'
+
+    tpls = [hjson_tpl, rtl_tpl, pkg_tpl]
+    outputs = [hjson_out, rtl_out, pkg_out]
+    names = ['clkmgr.hjson', 'clkmgr.sv', 'clkmgr_pkg.sv']
+
+    # clock classification
+    grps = top['clocks']['groups']
+
+    ft_clks = OrderedDict()
+    rg_clks = OrderedDict()
+    sw_clks = OrderedDict()
+    hint_clks = OrderedDict()
+
+    ft_clks   = {clk:src for grp in grps for (clk,src) in grp['clocks'].items()
+                 if grp['name'] == 'powerup'}
+
+    # root-gate clocks
+    rg_clks   = {clk:src for grp in grps for (clk,src) in grp['clocks'].items()
+                 if grp['name'] != 'powerup' and grp['sw_cg'] == 'no'}
+
+    # direct sw control clocks
+    sw_clks   = {clk:src for grp in grps for (clk,src) in grp['clocks'].items()
+                 if grp['sw_cg'] == 'yes'}
+
+    # sw hint clocks
+    hint_clks = {clk:src for grp in grps for (clk,src) in grp['clocks'].items()
+                 if grp['sw_cg'] == 'hint'}
+
+
+    out = StringIO()
+    for idx, tpl in enumerate(tpls):
+        with tpl.open(mode='r', encoding='UTF-8') as fin:
+            tpl = Template(fin.read())
+            try:
+                out = tpl.render(cfg=top,
+                                 ft_clks=ft_clks,
+                                 rg_clks=rg_clks,
+                                 sw_clks=sw_clks,
+                                 hint_clks=hint_clks)
+            except:  # noqa: E722
+                log.error(exceptions.text_error_template().render())
+
+        if out == "":
+            log.error("Cannot generate {}".format(names[idx]))
+            return
+
+        with outputs[idx].open(mode='w', encoding='UTF-8') as fout:
+            fout.write(genhdr + out)
+
+    # Generate reg files
+    with open(str(hjson_out), 'r') as out:
+        hjson_obj = hjson.load(out,
+                               use_decimal=True,
+                               object_pairs_hook=OrderedDict)
+    validate.validate(hjson_obj)
+    gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
 
 def generate_top_ral(top, ip_objs, out_path):
     # construct top ral block
@@ -571,6 +640,7 @@
         outdir = Path(args.outdir)
 
     out_path = Path(outdir)
+    cfg_path = Path(args.topcfg).parents[1]
 
     if not args.no_gen_hjson or args.hjson_only:
         # load top configuration
@@ -582,28 +652,38 @@
         except ValueError:
             raise SystemExit(sys.exc_info()[1])
 
+        # Create filtered list
+        filter_list = [module['name'] for module in topcfg['module']
+                       if 'generated' in module and module['generated'] == 'true']
+        log.info("Filtered list is {}".format(filter_list))
+
         topname = topcfg["name"]
 
         # Sweep the IP directory and gather the config files
         ip_dir = Path(__file__).parents[1] / 'hw/ip'
         ips = search_ips(ip_dir)
 
-        # exclude rv_plic (to use top_${topname} one) and
+        # exclude filtered IPs (to use top_${topname} one) and
         ips = [x for x in ips if not x.parents[1].name in filter_list]
 
+        # Hack alert
+        # Generate clkmgr.hjson here so that it can be included below
+        # Unlike other generated hjsons, clkmgr thankfully does not require
+        # ip.hjson information.  All the information is embedded within
+        # the top hjson file
+        amend_clocks(topcfg)
+        generate_clkmgr(topcfg, cfg_path, out_path)
+
         # It may require two passes to check if the module is needed.
         # TODO: first run of topgen will fail due to the absent of rv_plic.
         # It needs to run up to amend_interrupt in merge_top function
         # then creates rv_plic.hjson then run xbar generation.
         hjson_dir = Path(args.topcfg).parent
-        rv_plic_hjson = hjson_dir.parent / 'ip/rv_plic/data/autogen/rv_plic.hjson'
-        ips.append(rv_plic_hjson)
 
-        pinmux_hjson = hjson_dir.parent / 'ip/pinmux/data/autogen/pinmux.hjson'
-        ips.append(pinmux_hjson)
-
-        alert_handler_hjson = hjson_dir.parent / 'ip/alert_handler/data/autogen/alert_handler.hjson'
-        ips.append(alert_handler_hjson)
+        for ip in filter_list:
+            log.info("Appending {}".format(ip))
+            ip_hjson = hjson_dir.parent / "ip/{}/data/autogen/{}.hjson".format(ip,ip)
+            ips.append(ip_hjson)
 
         # load Hjson and pass validate from reggen
         try:
@@ -679,6 +759,7 @@
         if args.alert_handler_only:
             sys.exit()
 
+    # Generate Pinmux
     generate_pinmux(completecfg, out_path)
 
     # Generate xbars
diff --git a/util/topgen/__init__.py b/util/topgen/__init__.py
index ed22f14..8661abf 100644
--- a/util/topgen/__init__.py
+++ b/util/topgen/__init__.py
@@ -3,6 +3,6 @@
 # SPDX-License-Identifier: Apache-2.0
 
 # noqa: F401 These functions are used in topgen.py
-from .merge import merge_top  # noqa: F401
+from .merge import merge_top, amend_clocks  # noqa: F401
 from .validate import validate_top  # noqa: F401
 from .lib import search_ips, get_hjsonobj_xbars  # noqa: F401
diff --git a/util/topgen/merge.py b/util/topgen/merge.py
index c531a85..9c45c61 100644
--- a/util/topgen/merge.py
+++ b/util/topgen/merge.py
@@ -422,6 +422,7 @@
        Amend the clock connections of each entry to reflect the actual gated clock
     """
     clks_attr = top['clocks']
+    clk_paths = clks_attr['hier_paths']
     groups_in_top = [x["name"].lower() for x in clks_attr['groups']]
 
     # Default assignments
@@ -454,10 +455,22 @@
         # unique property of each group
         unique = clks_attr['groups'][cg_idx]['unique']
 
+        # src property of each group
+        src = clks_attr['groups'][cg_idx]['src']
+
         for port, clk in ep['clock_srcs'].items():
             ep_clks.append(clk)
 
-            if unique == "yes":
+            hier_name = clk_paths[src]
+
+            if src == 'ext':
+                # clock comes from top ports
+                if clk == 'main':
+                    clk_name = "clk_i"
+                else:
+                    clk_name = "clk_{}_i".format(clk)
+
+            elif unique == "yes":
                 # new unqiue clock name
                 clk_name = "clk_{}_{}".format(clk, ep_name)
 
@@ -469,7 +482,7 @@
             clks_attr['groups'][cg_idx]['clocks'][clk_name] = clk
 
             # add clock connections
-            clock_connections[port] = clk_name
+            clock_connections[port] = hier_name + clk_name
 
         # Add to endpoint structure
         ep['clock_connections'] = clock_connections
@@ -674,7 +687,7 @@
     # Assign clocks into appropriate groups
     # Note, amend_ip references clock information to establish async handling
     # as part of alerts.
-    amend_clocks(gencfg)
+    # amend_clocks(gencfg)
 
     # Add path names to declared resets
     amend_resets(gencfg)
diff --git a/util/topgen/validate.py b/util/topgen/validate.py
index f29fa76..e34e173 100644
--- a/util/topgen/validate.py
+++ b/util/topgen/validate.py
@@ -91,6 +91,7 @@
 
 clock_groups_required = {
     'name': ['s', 'name of clock group'],
+    'src': ['s', 'yes, no. This clock group is directly from source'],
     'sw_cg': ['s', 'yes, no, hint. Software clock gate attributes'],
 }
 clock_groups_optional = {
@@ -180,6 +181,12 @@
                 group['sw_cg']))
             error += 1
 
+        # Check combination of src and sw are valid
+        if group['src'] =='yes' and group['sw_cg'] != 'no':
+            log.error("Invalid combination of src and sw_cg: {} and {}".format(
+                group['src'], group['sw_cg']))
+            error += 1
+
         # Check combination of sw_cg and unique are valid
         unique = group['unique'] if 'unique' in group else 'no'
         if group['sw_cg'] == 'no' and unique != 'no':