diff --git a/doc/_extensions/zephyr/domain/__init__.py b/doc/_extensions/zephyr/domain/__init__.py
index 3081460254a2..38cacd20d119 100644
--- a/doc/_extensions/zephyr/domain/__init__.py
+++ b/doc/_extensions/zephyr/domain/__init__.py
@@ -36,7 +36,7 @@
from anytree import ChildResolverError, Node, PreOrderIter, Resolver, search
from docutils import nodes
-from docutils.parsers.rst import directives
+from docutils.parsers.rst import directives, roles
from docutils.statemachine import StringList
from sphinx import addnodes
from sphinx.application import Sphinx
@@ -797,55 +797,33 @@ def run(self):
result_nodes.append(note)
return result_nodes
- # Add the note before any tables
- note = nodes.admonition(classes=["legend"])
- note += nodes.title(text="Table Legend", classes=["note"])
-
- legend = nodes.definition_list(classes=["supported-hardware field-list"])
-
- def add_legend_item(legend_list, term_text, term_classes, definition_text):
- dl_item = nodes.definition_list_item()
- dt = nodes.term()
- dt += nodes.inline("", term_text, classes=term_classes)
- dd = nodes.definition()
- dd += nodes.Text(definition_text)
- dl_item += dt
- dl_item += dd
- legend_list += dl_item
-
- add_legend_item(
- legend, "on-chip", ["location-chip", "onchip"], "Feature integrated in the SoC."
- )
- add_legend_item(
- legend, "on-board", ["location-chip", "onboard"], "Feature present on the board."
- )
- add_legend_item(
- legend,
- "2",
- ["count", "okay-count"],
- "Number of instances of the feature that are present and enabled.",
- )
- add_legend_item(
- legend,
- "2",
- ["count", "disabled-count"],
- "Number of instances of the feature that are present but initially disabled.",
- )
-
- dl_item = nodes.definition_list_item()
- dt = nodes.term()
- dt += nodes.literal(text="vnd,foo")
- dd = nodes.definition()
- dd += nodes.Text(
- "Compatible string for the Devicetree binding matching the feature. "
- "Click on the link to checkout the binding documentation."
- )
- dl_item += dt
- dl_item += dd
- legend += dl_item
-
- note += legend
- result_nodes.append(note)
+ html_contents = """
+
+ -
+ on-chip /
+ on-board
+
+ -
+ Feature integrated in the SoC / present on the board.
+
+ -
+ 2 /
+ 2
+
+ -
+ Number of instances that are enabled / disabled.
+ Click on the label to see the first instance of this feature in DTS source files.
+
+ -
+
vnd,foo
+
+ -
+ Compatible string for the Devicetree binding matching the feature.
+ Click on the link to view the binding documentation.
+
+
+
"""
+ result_nodes.append(nodes.raw("", html_contents, format="html"))
for target, features in sorted(supported_features.items()):
if not features:
@@ -893,7 +871,7 @@ def feature_sort_key(feature):
for i, (key, value) in enumerate(items):
row = nodes.row()
- if value.get("disabled_count", 0) > 0 and value.get("okay_count", 0) == 0:
+ if value.get("disabled_nodes", []) and not value.get("okay_nodes", []):
row["classes"].append("disabled")
# TYPE column
@@ -934,22 +912,39 @@ def feature_sort_key(feature):
desc_para += nodes.Text(value["description"])
# Add count indicators for okay and not-okay instances
- okay_count = value.get("okay_count", 0)
- disabled_count = value.get("disabled_count", 0)
+ okay_nodes = value.get("okay_nodes", [])
+ disabled_nodes = value.get("disabled_nodes", [])
- if okay_count > 0:
- okay_count_indicator = nodes.inline(
- classes=["count", "okay-count"],
- text=str(okay_count),
- )
- desc_para += okay_count_indicator
+ role_fn, _ = roles.role(
+ "zephyr_file", self.state_machine.language, self.lineno, self.state.reporter
+ )
+
+ def create_count_indicator(nodes_list, class_type, role_function=role_fn):
+ if not nodes_list:
+ return None
+
+ count = len(nodes_list)
+
+ if role_function is None:
+ return nodes.inline(
+ classes=["count", f"{class_type}-count"], text=str(count)
+ )
- if disabled_count > 0:
- disabled_count_indicator = nodes.inline(
- classes=["count", "disabled-count"],
- text=str(disabled_count),
+ # Create a reference to the first node in the list
+ first_node = nodes_list[0]
+ file_ref = f"{count} <{first_node['filename']}#L{first_node['lineno']}>"
+
+ role_nodes, _ = role_function(
+ "zephyr_file", file_ref, file_ref, self.lineno, self.state.inliner
)
- desc_para += disabled_count_indicator
+
+ count_node = role_nodes[0]
+ count_node["classes"] = ["count", f"{class_type}-count"]
+
+ return count_node
+
+ desc_para += create_count_indicator(okay_nodes, "okay")
+ desc_para += create_count_indicator(disabled_nodes, "disabled")
desc_entry += desc_para
row += desc_entry
diff --git a/doc/_extensions/zephyr/domain/static/css/board.css b/doc/_extensions/zephyr/domain/static/css/board.css
index 1224067bfff2..5a50c419fb03 100644
--- a/doc/_extensions/zephyr/domain/static/css/board.css
+++ b/doc/_extensions/zephyr/domain/static/css/board.css
@@ -83,7 +83,6 @@
.legend {
font-size: 0.9em;
- max-width: 600px;
border-radius: 6px;
margin: auto;
@@ -179,6 +178,7 @@
font-size: 0.7em;
font-weight: 600;
margin-left: 4px;
+ padding-right: 6px !important;
&::before {
content: "×";
diff --git a/doc/_scripts/gen_boards_catalog.py b/doc/_scripts/gen_boards_catalog.py
index 681b7a735b6c..482fbf208f57 100755
--- a/doc/_scripts/gen_boards_catalog.py
+++ b/doc/_scripts/gen_boards_catalog.py
@@ -254,7 +254,7 @@ def get_catalog(generate_hw_features=False):
# Use pre-gathered build info and DTS files
if board.name in board_devicetrees:
for board_target, edt in board_devicetrees[board.name].items():
- target_features = {}
+ features = {}
for node in edt.nodes:
if node.binding_path is None:
continue
@@ -271,6 +271,7 @@ def get_catalog(generate_hw_features=False):
description = DeviceTreeUtils.get_cached_description(node)
filename = node.filename
+ lineno = node.lineno
locations = set()
if Path(filename).is_relative_to(ZEPHYR_BASE):
filename = Path(filename).relative_to(ZEPHYR_BASE)
@@ -279,23 +280,30 @@ def get_catalog(generate_hw_features=False):
else:
locations.add("soc")
- existing_feature = target_features.get(binding_type, {}).get(
+ existing_feature = features.get(binding_type, {}).get(
node.matching_compat
)
+
+ node_info = {"filename": str(filename), "lineno": lineno}
+ node_list_key = "okay_nodes" if node.status == "okay" else "disabled_nodes"
+
if existing_feature:
locations.update(existing_feature["locations"])
- key = "okay_count" if node.status == "okay" else "disabled_count"
- existing_feature[key] = existing_feature.get(key, 0) + 1
- else:
- key = "okay_count" if node.status == "okay" else "disabled_count"
- target_features.setdefault(binding_type, {})[node.matching_compat] = {
- "description": description,
- "locations": locations,
- key: 1
- }
+ existing_feature.setdefault(node_list_key, []).append(node_info)
+ continue
+
+ feature_data = {
+ "description": description,
+ "locations": locations,
+ "okay_nodes": [],
+ "disabled_nodes": [],
+ }
+ feature_data[node_list_key].append(node_info)
+
+ features.setdefault(binding_type, {})[node.matching_compat] = feature_data
# Store features for this specific target
- supported_features[board_target] = target_features
+ supported_features[board_target] = features
# Grab all the twister files for this board and use them to figure out all the archs it
# supports.