[topgen] Generate Clock Description for SW
This generates indexes that can be used by `dif_clkmgr` to index into
the memory-mapped registers, in order to control specific, named,
clocks. Not all clocks are named, nor are they all software-controlled,
but the logic here matches the logic that generates the clock manger
description.
Signed-off-by: Sam Elliott <selliott@lowrisc.org>
diff --git a/hw/top_earlgrey/data/top_earlgrey.h.tpl b/hw/top_earlgrey/data/top_earlgrey.h.tpl
index 07a90ef..56caa5e 100644
--- a/hw/top_earlgrey/data/top_earlgrey.h.tpl
+++ b/hw/top_earlgrey/data/top_earlgrey.h.tpl
@@ -159,6 +159,20 @@
*/
${helper.pwrmgr_reset_requests.render()}
+/**
+ * Clock Manager Software-Controlled ("Gated") Clocks.
+ *
+ * The Software has full control over these clocks.
+ */
+${helper.clkmgr_gateable_clocks.render()}
+
+/**
+ * Clock Manager Software-Hinted Clocks.
+ *
+ * The Software has partial control over these clocks. It can ask them to stop,
+ * but the clock manager is in control of whether the clock actually is stopped.
+ */
+${helper.clkmgr_hintable_clocks.render()}
// Header Extern Guard
#ifdef __cplusplus
diff --git a/hw/top_earlgrey/sw/autogen/top_earlgrey.h b/hw/top_earlgrey/sw/autogen/top_earlgrey.h
index 533d463..57f56ca 100644
--- a/hw/top_earlgrey/sw/autogen/top_earlgrey.h
+++ b/hw/top_earlgrey/sw/autogen/top_earlgrey.h
@@ -831,6 +831,30 @@
kTopEarlgreyPowerManagerResetRequestsLast = 0, /**< \internal Last valid pwrmgr reset_request signal */
} top_earlgrey_power_manager_reset_requests_t;
+/**
+ * Clock Manager Software-Controlled ("Gated") Clocks.
+ *
+ * The Software has full control over these clocks.
+ */
+typedef enum top_earlgrey_gateable_clocks {
+ kTopEarlgreyGateableClocksIoDiv4Peri = 0, /**< Clock clk_io_div4_peri in group peri */
+ kTopEarlgreyGateableClocksUsbPeri = 1, /**< Clock clk_usb_peri in group peri */
+ kTopEarlgreyGateableClocksLast = 1, /**< \internal Last Valid Gateable Clock */
+} top_earlgrey_gateable_clocks_t;
+
+/**
+ * Clock Manager Software-Hinted Clocks.
+ *
+ * The Software has partial control over these clocks. It can ask them to stop,
+ * but the clock manager is in control of whether the clock actually is stopped.
+ */
+typedef enum top_earlgrey_hintable_clocks {
+ kTopEarlgreyHintableClocksMainAes = 0, /**< Clock clk_main_aes in group trans */
+ kTopEarlgreyHintableClocksMainHmac = 1, /**< Clock clk_main_hmac in group trans */
+ kTopEarlgreyHintableClocksMainKmac = 2, /**< Clock clk_main_kmac in group trans */
+ kTopEarlgreyHintableClocksMainOtbn = 3, /**< Clock clk_main_otbn in group trans */
+ kTopEarlgreyHintableClocksLast = 3, /**< \internal Last Valid Hintable Clock */
+} top_earlgrey_hintable_clocks_t;
// Header Extern Guard
#ifdef __cplusplus
diff --git a/util/topgen/c.py b/util/topgen/c.py
index 070d218..d062825 100644
--- a/util/topgen/c.py
+++ b/util/topgen/c.py
@@ -48,6 +48,9 @@
def as_c_type(self):
return self.as_snake_case() + "_t"
+ def remove_part(self, part_to_remove):
+ return Name([p for p in self.parts if p != part_to_remove])
+
class MemoryRegion(object):
def __init__(self, name, base_addr, size_bytes):
@@ -150,6 +153,7 @@
self._init_pwrmgr_wakeups()
self._init_rstmgr_sw_rsts()
self._init_pwrmgr_reset_requests()
+ self._init_clkmgr_clocks()
def modules(self):
return [(m["name"],
@@ -404,3 +408,43 @@
enum.add_last_constant("Last valid pwrmgr reset_request signal")
self.pwrmgr_reset_requests = enum
+
+ def _init_clkmgr_clocks(self):
+ """
+ Creates CEnums for accessing the software-controlled clocks in the
+ design.
+
+ The logic here matches the logic in topgen.py in how it instantiates the
+ clock manager with the described clocks.
+
+ We differentiate "gateable" clocks and "hintable" clocks because the
+ clock manager has separate register interfaces for each group.
+ """
+
+
+ aon_clocks = set()
+ for src in self.top['clocks']['srcs'] + self.top['clocks']['derived_srcs']:
+ if src['aon'] == 'yes':
+ aon_clocks.add(src['name'])
+
+ gateable_clocks = CEnum(self._top_name + Name(["gateable", "clocks"]))
+ hintable_clocks = CEnum(self._top_name + Name(["hintable", "clocks"]))
+
+ # This replicates the behaviour in `topgen.py` in deriving `hints` and
+ # `sw_clocks`.
+ for group in self.top['clocks']['groups']:
+ for (name, source) in group['clocks'].items():
+ if source not in aon_clocks:
+ # All these clocks start with `clk_` which is redundant.
+ clock_name = Name.from_snake_case(name).remove_part("clk")
+ docstring = "Clock {} in group {}".format(name, group['name'])
+ if group["sw_cg"] == "yes":
+ gateable_clocks.add_constant(clock_name, docstring)
+ elif group["sw_cg"] == "hint":
+ hintable_clocks.add_constant(clock_name, docstring)
+
+ gateable_clocks.add_last_constant("Last Valid Gateable Clock")
+ hintable_clocks.add_last_constant("Last Valid Hintable Clock")
+
+ self.clkmgr_gateable_clocks = gateable_clocks
+ self.clkmgr_hintable_clocks = hintable_clocks