[clkmgr, rstmgr] Add clkmgr/rstmgr option to export selective clocks/resets
- The clocks / resets can be exported to multiple interfaces
- At the moment there is only ast
Signed-off-by: Timothy Chen <timothytim@google.com>
[topgen] automatically add exported clocks/resets to intermodule
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 2182891..5c01a8e 100644
--- a/hw/ip/clkmgr/data/clkmgr.hjson.tpl
+++ b/hw/ip/clkmgr/data/clkmgr.hjson.tpl
@@ -57,6 +57,16 @@
},
% endfor
+ // Exported clocks
+% for intf in export_clks:
+ { struct: "clkmgr_${intf}_out",
+ type: "uni",
+ name: "clocks_${intf}",
+ act: "req",
+ package: "clkmgr_pkg",
+ },
+% endfor
+
{ struct: "pwr_clk",
type: "req_rsp",
name: "pwr",
diff --git a/hw/ip/clkmgr/data/clkmgr.sv.tpl b/hw/ip/clkmgr/data/clkmgr.sv.tpl
index fc484ef..d093eb0 100644
--- a/hw/ip/clkmgr/data/clkmgr.sv.tpl
+++ b/hw/ip/clkmgr/data/clkmgr.sv.tpl
@@ -47,6 +47,9 @@
input clk_hint_status_t status_i,
// clock output interface
+% for intf in export_clks:
+ output clkmgr_${intf}_out_t clocks_${intf}_o,
+% endfor
output clkmgr_out_t clocks_o
);
@@ -227,6 +230,17 @@
assign hw2reg.clk_hints_status.${k}_val.d = ${k}_en;
% endfor
+ ////////////////////////////////////////////////////
+ // Exported clocks
+ ////////////////////////////////////////////////////
+
+% for intf, eps in export_clks.items():
+ % for ep, clks in eps.items():
+ % for clk in clks:
+ assign clocks_${intf}_o.clk_${intf}_${ep}_${clk} = clocks_o.clk_${clk};
+ % endfor
+ % endfor
+% endfor
////////////////////////////////////////////////////
// Assertions
diff --git a/hw/ip/clkmgr/data/clkmgr_pkg.sv.tpl b/hw/ip/clkmgr/data/clkmgr_pkg.sv.tpl
index bc90f85..97b091f 100644
--- a/hw/ip/clkmgr/data/clkmgr_pkg.sv.tpl
+++ b/hw/ip/clkmgr/data/clkmgr_pkg.sv.tpl
@@ -35,6 +35,16 @@
} clkmgr_out_t;
+% for intf, eps in export_clks.items():
+ typedef struct packed {
+ % for ep, clks in eps.items():
+ % for clk in clks:
+ logic clk_${intf}_${ep}_${clk};
+ % endfor
+ % endfor
+ } clkmgr_${intf}_out_t;
+% endfor
+
typedef struct packed {
logic [${num_hints}-1:0] idle;
} clk_hint_status_t;
diff --git a/hw/ip/rstmgr/data/rstmgr.hjson.tpl b/hw/ip/rstmgr/data/rstmgr.hjson.tpl
index ef27af8..6dd745c 100644
--- a/hw/ip/rstmgr/data/rstmgr.hjson.tpl
+++ b/hw/ip/rstmgr/data/rstmgr.hjson.tpl
@@ -56,6 +56,16 @@
act: "rcv",
package: "rstmgr_pkg", // Origin package (only needs for the req)
}
+
+ // Exported resets
+% for intf in export_rsts:
+ { struct: "rstmgr_${intf}_out",
+ type: "uni",
+ name: "resets_${intf}",
+ act: "req",
+ package: "rstmgr_pkg", // Origin package (only needs for the req)
+ }
+% endfor
],
registers: [
diff --git a/hw/ip/rstmgr/data/rstmgr.sv.tpl b/hw/ip/rstmgr/data/rstmgr.sv.tpl
index f285cc7..66d267d 100644
--- a/hw/ip/rstmgr/data/rstmgr.sv.tpl
+++ b/hw/ip/rstmgr/data/rstmgr.sv.tpl
@@ -35,7 +35,11 @@
input rstmgr_peri_t peri_i,
// Interface to alert handler
- // always on resets
+
+ // reset outputs
+% for intf in export_rsts:
+ output rstmgr_${intf}_out_t resets_${intf}_o,
+% endfor
output rstmgr_out_t resets_o
);
@@ -182,6 +186,17 @@
);
////////////////////////////////////////////////////
+ // Exported resets //
+ ////////////////////////////////////////////////////
+% for intf, eps in export_rsts.items():
+ % for ep, rsts in eps.items():
+ % for rst in rsts:
+ assign resets_${intf}_o.rst_${intf}_${ep}_${rst}_n = resets_o.rst_${rst}_n;
+ % endfor
+ % endfor
+% endfor
+
+ ////////////////////////////////////////////////////
// Assertions //
////////////////////////////////////////////////////
diff --git a/hw/ip/rstmgr/data/rstmgr_pkg.sv.tpl b/hw/ip/rstmgr/data/rstmgr_pkg.sv.tpl
index 8db2354..7de607e 100644
--- a/hw/ip/rstmgr/data/rstmgr_pkg.sv.tpl
+++ b/hw/ip/rstmgr/data/rstmgr_pkg.sv.tpl
@@ -45,6 +45,17 @@
logic ndmreset_req;
} rstmgr_cpu_t;
+ // exported resets
+% for intf, eps in export_rsts.items():
+ typedef struct packed {
+ % for ep, rsts in eps.items():
+ % for rst in rsts:
+ logic rst_${intf}_${ep}_${rst}_n;
+ % endfor
+ % endfor
+ } rstmgr_${intf}_out_t;
+% endfor
+
// default value for rstmgr_ast_rsp_t (for dangling ports)
parameter rstmgr_cpu_t RSTMGR_CPU_DEFAULT = '{
rst_cpu_n: 1'b1,
diff --git a/hw/top_earlgrey/data/top_earlgrey.hjson b/hw/top_earlgrey/data/top_earlgrey.hjson
index dbca431..b0cfd4f 100644
--- a/hw/top_earlgrey/data/top_earlgrey.hjson
+++ b/hw/top_earlgrey/data/top_earlgrey.hjson
@@ -288,6 +288,7 @@
type: "usbdev",
clock_srcs: {clk_i: "io", clk_usb_48mhz_i: "usb"},
clock_group: "peri",
+ clock_reset_export: ["ast"],
reset_connections: {rst_ni: "sys_io", rst_usb_48mhz_ni: "usb"},
base_addr: "0x40150000",
},
@@ -295,6 +296,7 @@
type: "sensor_ctrl",
clock_srcs: {clk_i: "io"},
clock_group: "secure",
+ clock_reset_export: ["ast"],
reset_connections: {rst_ni: "sys_io"},
base_addr: "0x40170000",
top_only: "true"
@@ -414,7 +416,7 @@
'clkmgr.clk_main': 'clk_main',
'clkmgr.clk_io': 'clk_io',
'clkmgr.clk_usb': 'clk_usb',
- 'clkmgr.clk_aon': 'clk_aon'
+ 'clkmgr.clk_aon': 'clk_aon',
'rstmgr.ast': '',
'pwrmgr.pwr_ast': '',
'sensor_ctrl.ast_alert': '',
diff --git a/util/topgen.py b/util/topgen.py
index 130fa65..73d9779 100755
--- a/util/topgen.py
+++ b/util/topgen.py
@@ -556,6 +556,7 @@
ft_clks=ft_clks,
rg_clks=rg_clks,
sw_clks=sw_clks,
+ export_clks=top['exported_clks'],
hint_clks=hint_clks)
except: # noqa: E722
log.error(exceptions.text_error_template().render())
@@ -683,7 +684,8 @@
out = tpl.render(clks=clks,
sw_rsts=sw_rsts,
output_rsts=output_rsts,
- leaf_rsts=leaf_rsts)
+ leaf_rsts=leaf_rsts,
+ export_rsts=topcfg['exported_rsts'])
except: # noqa: E722
log.error(exceptions.text_error_template().render())
diff --git a/util/topgen/merge.py b/util/topgen/merge.py
index 6ff00e0..b5cce58 100644
--- a/util/topgen/merge.py
+++ b/util/topgen/merge.py
@@ -472,6 +472,15 @@
return result
+# Check if the export field already exists
+# If yes, return it
+# If no, set a default and return that
+def check_clk_rst_export(module):
+ if 'clock_reset_export' not in module:
+ module['clock_reset_export'] = []
+ return module['clock_reset_export']
+
+
def amend_clocks(top: OrderedDict):
"""Add a list of clocks to each clock group
Amend the clock connections of each entry to reflect the actual gated clock
@@ -479,6 +488,7 @@
clks_attr = top['clocks']
clk_paths = clks_attr['hier_paths']
groups_in_top = [x["name"].lower() for x in clks_attr['groups']]
+ exported_clks = OrderedDict()
# Assign default parameters to source clocks
for src in clks_attr['srcs']:
@@ -501,6 +511,9 @@
clock_connections = OrderedDict()
+ # Ensure each module has a default case
+ export_if = check_clk_rst_export(ep)
+
# if no clock group assigned, default is unique
ep['clock_group'] = 'secure' if 'clock_group' not in ep else ep[
'clock_group']
@@ -522,22 +535,25 @@
for port, clk in ep['clock_srcs'].items():
ep_clks.append(clk)
+ name = ''
hier_name = clk_paths[src]
if src == 'ext':
# clock comes from top ports
if clk == 'main':
- clk_name = "clk_i"
+ name = "i"
else:
- clk_name = "clk_{}_i".format(clk)
+ name = "{}_i".format(clk)
elif unique == "yes":
# new unqiue clock name
- clk_name = "clk_{}_{}".format(clk, ep_name)
+ name = "{}_{}".format(clk, ep_name)
else:
# new group clock name
- clk_name = "clk_{}_{}".format(clk, ep_grp)
+ name = "{}_{}".format(clk, ep_grp)
+
+ clk_name = "clk_" + name
# add clock to a particular group
clks_attr['groups'][cg_idx]['clocks'][clk_name] = clk
@@ -545,9 +561,31 @@
# add clock connections
clock_connections[port] = hier_name + clk_name
+ # clocks for this module are exported
+ for intf in export_if:
+ log.info("{} export clock name is {}".format(ep_name, name))
+
+ # create dict entry if it does not exit
+ if intf not in exported_clks:
+ exported_clks[intf] = OrderedDict()
+
+ # if first time encounter end point, declare
+ if ep_name not in exported_clks[intf]:
+ exported_clks[intf][ep_name] = []
+
+ # append clocks
+ exported_clks[intf][ep_name].append(name)
+
# Add to endpoint structure
ep['clock_connections'] = clock_connections
+ # add entry to top level json
+ top['exported_clks'] = exported_clks
+
+ # add entry to inter_module automatically
+ for intf in top['exported_clks']:
+ top['inter_module']['external']['clkmgr.clocks_{}'.format(intf)] = "clks_{}".format(intf)
+
def amend_resets(top):
"""Add a path variable to reset declaration
@@ -572,6 +610,32 @@
log.error("{} type is invalid".format(reset["type"]))
top["reset_paths"] = reset_paths
+
+ # Generate exported reset list
+ exported_rsts = OrderedDict()
+ for module in top["module"]:
+
+ # This code is here to ensure if amend_clocks/resets switched order
+ # everything would still work
+ export_if = check_clk_rst_export(module)
+
+ # There may be multiple export interfaces
+ for intf in export_if:
+ # create dict entry if it does not exit
+ if intf not in exported_rsts:
+ exported_rsts[intf] = OrderedDict()
+
+ # grab directly from reset_connections definition
+ rsts = [rst for rst in module['reset_connections'].values()]
+ exported_rsts[intf][module['name']] = rsts
+
+ # add entry to top level json
+ top['exported_rsts'] = exported_rsts
+
+ # add entry to inter_module automatically
+ for intf in top['exported_rsts']:
+ top['inter_module']['external']['rstmgr.resets_{}'.format(intf)] = "rsts_{}".format(intf)
+
return