[1/1] lib: utils/fdt: Parse for UART "clocks" property if "clock-frequency" is absent

Tan En De ende.tan at starfivetech.com
Wed Apr 5 23:26:22 PDT 2023


For UART node, current implementation of fdt_parse_uart_node_common() checks for "clock-frequency" property only.
However, for UART node that uses more than one clock,
"clock-frequency" may need to be parsed from the phandle specified in "clocks" property.
So, this commit adds in logic to parse "clocks" property if "clock-frequency" is absent.

Signed-off-by: Tan En De <ende.tan at starfivetech.com>
Signed-off-by: Tan Jun Liang <junliang.tan at starfivetech.com>
---
 include/sbi_utils/fdt/fdt_helper.h |  6 +++
 lib/utils/fdt/fdt_helper.c         | 65 +++++++++++++++++++++++++++++-
 2 files changed, 69 insertions(+), 2 deletions(-)

diff --git a/include/sbi_utils/fdt/fdt_helper.h b/include/sbi_utils/fdt/fdt_helper.h
index 39d7f3a..d84040e 100644
--- a/include/sbi_utils/fdt/fdt_helper.h
+++ b/include/sbi_utils/fdt/fdt_helper.h
@@ -32,6 +32,12 @@ struct platform_uart_data {
 	unsigned long reg_shift;
 	unsigned long reg_io_width;
 	unsigned long reg_offset;
+	/*
+	 * For multi-clock UART node.
+	 * clock_index shall be set to zero-indexed main clock's index in the "clocks" list,
+	 * from which freq will be obtained for baud calculation.
+	 */
+	unsigned long clock_index;
 };
 
 const struct fdt_match *fdt_match_node(void *fdt, int nodeoff,
diff --git a/lib/utils/fdt/fdt_helper.c b/lib/utils/fdt/fdt_helper.c
index 48bc2fe..d68d886 100644
--- a/lib/utils/fdt/fdt_helper.c
+++ b/lib/utils/fdt/fdt_helper.c
@@ -313,6 +313,62 @@ int fdt_parse_timebase_frequency(void *fdt, unsigned long *freq)
 	return 0;
 }
 
+/*
+ * For multi-clock UART node.
+ * Parse "clocks" property in UART node to set uart->freq.
+ * "clocks" property is an array of clock phandle and clock specifier pairs.
+ * Before calling this function, uart->clock_index shall be set with
+ * the index of the pair containing the main UART clock's phandle,
+ * which baudrate calculation will be based on.
+ * Return 0 on success, else return -1.
+ */
+static int fdt_parse_uart_clocks_prop(void *fdt, int nodeoffset,
+				struct platform_uart_data *uart)
+{
+	const fdt32_t *clocks_val, *clock_cells_val, *clock_frequency_val;
+	uint32_t clock_phandle, cell_index, clock_cells;
+	int clocks_len, clock_offset, clock_cells_len, clock_frequency_len;
+	unsigned long clock_index = uart->clock_index;
+
+	/* clocks_val is a flattened array of values, made from the phandle and specifier pairs. */
+	clocks_val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "clocks", &clocks_len);
+	if (!(clocks_len > 0 && clocks_val))
+		return -1;
+
+	cell_index = 0; /* index into the clocks_val */
+	for (int i = 0; i <= clock_index; i++) {
+		/* In case of out-of-bound access to the clocks_val array, return -1. */
+		if (cell_index + 1 > clocks_len)
+			return -1;
+		/* Else, parse the phandle */
+		clock_phandle = fdt32_to_cpu(clocks_val[cell_index]);
+		clock_offset = fdt_node_offset_by_phandle(fdt, clock_phandle);
+		/*
+		 * "#clock-cells" is a required property,
+		 * it tells how many cells the clock specifier takes.
+		 */
+		clock_cells_val = (fdt32_t *)fdt_getprop(fdt, clock_offset, "#clock-cells", &clock_cells_len);
+		if (clock_cells_len > 0 && clock_cells_val)
+			clock_cells = fdt32_to_cpu(*clock_cells_val);
+		else
+			return -1;
+		/*
+		 * Advance clock_index to get cell index to next phandle.
+		 * Each phandle and clock specifier pair consists of
+		 * 1 phandle and clock_cells number of specifiers.
+		 */
+		cell_index += 1 + clock_cells;
+	}
+	/* Finally, obtain the uart->freq from "clock-freqeuncy" property */
+	clock_frequency_val = (fdt32_t *)fdt_getprop(fdt, clock_offset, "clock-frequency", &clock_frequency_len);
+	if (clock_frequency_len > 0 && clock_frequency_val)
+		uart->freq = fdt32_to_cpu(*clock_frequency_val);
+	else
+		return -1;
+
+	return 0;
+}
+
 static int fdt_parse_uart_node_common(void *fdt, int nodeoffset,
 				      struct platform_uart_data *uart,
 				      unsigned long default_freq,
@@ -338,8 +394,13 @@ static int fdt_parse_uart_node_common(void *fdt, int nodeoffset,
 	val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "clock-frequency", &len);
 	if (len > 0 && val)
 		uart->freq = fdt32_to_cpu(*val);
-	else
-		uart->freq = default_freq;
+	else {
+		/* If "clock-frequency" property is absent, try parse for "clocks" property */
+		rc = fdt_parse_uart_clocks_prop(fdt, nodeoffset, uart);
+		/* Fall back to default frequency in case of failure to parse */
+		if (rc < 0)
+			uart->freq = default_freq;
+	}
 
 	val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "current-speed", &len);
 	if (len > 0 && val)
-- 
2.34.1




More information about the opensbi mailing list