aboutsummaryrefslogtreecommitdiff
path: root/lib/utils/fdt/fdt_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/utils/fdt/fdt_helper.c')
-rw-r--r--lib/utils/fdt/fdt_helper.c116
1 files changed, 116 insertions, 0 deletions
diff --git a/lib/utils/fdt/fdt_helper.c b/lib/utils/fdt/fdt_helper.c
index 2ea52ca..81617c9 100644
--- a/lib/utils/fdt/fdt_helper.c
+++ b/lib/utils/fdt/fdt_helper.c
@@ -11,6 +11,7 @@
#include <sbi/sbi_console.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_scratch.h>
+#include <sbi_utils/fdt/fdt_helper.h>
void fdt_cpu_fixup(void *fdt)
{
@@ -198,3 +199,118 @@ void fdt_fixups(void *fdt)
fdt_reserved_memory_fixup(fdt);
}
+
+static int fdt_get_node_addr_size(void *fdt, int node, unsigned long *addr,
+ unsigned long *size)
+{
+ int parent, len, i;
+ int cell_addr, cell_size;
+ const fdt32_t *prop_addr, *prop_size;
+ uint64_t temp = 0;
+
+ parent = fdt_parent_offset(fdt, node);
+ if (parent < 0)
+ return parent;
+ cell_addr = fdt_address_cells(fdt, parent);
+ if (cell_addr < 1)
+ return SBI_ENODEV;
+
+ cell_size = fdt_size_cells(fdt, parent);
+ if (cell_size < 0)
+ return SBI_ENODEV;
+
+ prop_addr = fdt_getprop(fdt, node, "reg", &len);
+ if (!prop_addr)
+ return SBI_ENODEV;
+ prop_size = prop_addr + cell_addr;
+
+ if (addr) {
+ for (i = 0; i < cell_addr; i++)
+ temp = (temp << 32) | fdt32_to_cpu(*prop_addr++);
+ *addr = temp;
+ }
+ temp = 0;
+
+ if (size) {
+ for (i = 0; i < cell_size; i++)
+ temp = (temp << 32) | fdt32_to_cpu(*prop_size++);
+ *size = temp;
+ }
+
+ return 0;
+}
+
+int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
+ const char *compatible)
+{
+ int nodeoffset, len, rc;
+ fdt32_t *val;
+ unsigned long reg_addr, reg_size;
+
+ /**
+ * TODO: We don't know how to handle multiple nodes with the same
+ * compatible sring. Just return the first node for now.
+ */
+
+ nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compatible);
+ if (nodeoffset < 0)
+ return nodeoffset;
+
+ rc = fdt_get_node_addr_size(fdt, nodeoffset, &reg_addr, &reg_size);
+ if (rc < 0 || !reg_addr || !reg_size)
+ return SBI_ENODEV;
+ uart->addr = reg_addr;
+
+ /**
+ * UART address is mandaotry. clock-frequency and current-speed may not
+ * be present. Don't return error.
+ */
+ val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "clock-frequency", &len);
+ if (len > 0 && val)
+ uart->freq = fdt32_to_cpu(*val);
+
+ val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "current-speed", &len);
+ if (len > 0 && val)
+ uart->baud = fdt32_to_cpu(*val);
+
+ return 0;
+}
+
+int fdt_parse_plic(void *fdt, struct platform_plic_data *plic,
+ const char *compatible)
+{
+ int nodeoffset, len, rc;
+ const fdt32_t *val;
+ unsigned long reg_addr, reg_size;
+
+ nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compatible);
+ if (nodeoffset < 0)
+ return nodeoffset;
+
+ rc = fdt_get_node_addr_size(fdt, nodeoffset, &reg_addr, &reg_size);
+ if (rc < 0 || !reg_addr || !reg_size)
+ return SBI_ENODEV;
+ plic->addr = reg_addr;
+
+ val = fdt_getprop(fdt, nodeoffset, "riscv,ndev", &len);
+ if (len > 0)
+ plic->num_src = fdt32_to_cpu(*val);
+
+ return 0;
+}
+
+int fdt_parse_clint(void *fdt, unsigned long *clint_addr,
+ const char *compatible)
+{
+ int nodeoffset, rc;
+
+ nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compatible);
+ if (nodeoffset < 0)
+ return nodeoffset;
+
+ rc = fdt_get_node_addr_size(fdt, nodeoffset, clint_addr, NULL);
+ if (rc < 0 || !clint_addr)
+ return SBI_ENODEV;
+
+ return 0;
+}