
Hi FDT experts,
some time ago I posted a patch to fix U-Boot's approach to set all ns16550 compatible nodes' clock-frequency property in ppc4xx device tree's:
do_fixup_by_compat_u32(blob, "ns16550", "clock-frequency", gd->uart_clk, 1);
Typically this works fine. It is intended to configure all CPU internal UART's clock. We have some additional UARTs attached to an external bus. From the device tree's point of view they have a different path, but are also ns16550 compatible.
So the above line will also overwrite thier clock-frequency. This must not be done, because they have a separate external clock and the value in the device tree is correct!
Now I want to replace the above code to only touch the ns16550 compatible nodes that are direct childs of /plb/opb. Not those under /plb/ebc and even not those under /plb/opb/ebc. This is not easy to do with the fdt API. Below you find my first and dirty hack.
Isn't there a more simple way to do so? Don't bother me about the printf, variable names etc. It's just for discussion.
Please tell me if I have to explain my code :-)
Matthias
From c915c5a8f38940cf0a5047863fb953712049e0be Mon Sep 17 00:00:00 2001 From: Matthias Fuchs matthias.fuchs@esd-electronics.com Date: Fri, 30 Jan 2009 11:00:33 +0100 Subject: [PATCH] ppc4xx: Only fixup opb attached (CPU internal) UARTs
Signed-off-by: Matthias Fuchs matthias.fuchs@esd-electronics.com --- cpu/ppc4xx/fdt.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 65 insertions(+), 0 deletions(-)
diff --git a/cpu/ppc4xx/fdt.c b/cpu/ppc4xx/fdt.c index c55e1cf..f668ac6 100644 --- a/cpu/ppc4xx/fdt.c +++ b/cpu/ppc4xx/fdt.c @@ -110,9 +110,48 @@ void fdt_pcie_setup(void *blob) } }
+int ft_path_end_offset(void *blob, char *path) +{ + int start, stop; + int off; + uint32_t tag; + int nextoffset; + int level = 0; + + off = fdt_path_offset(blob, path); + if (off < 0) + return -1; + + stop = start = off; + + while (stop == start) { + tag = fdt_next_tag(blob, off, &nextoffset); + switch(tag) { + case FDT_BEGIN_NODE: + level++; + break; + + case FDT_END_NODE: + if (level == 1) + stop = off; + level--; + break; + + default: + break; + } + off = nextoffset; + } + + return stop; +} + void ft_cpu_setup(void *blob, bd_t *bd) { sys_info_t sys_info; + int start, stop; + int start2, stop2; + int off;
get_sys_info(&sys_info);
@@ -135,7 +174,33 @@ void ft_cpu_setup(void *blob, bd_t *bd) /* * Setup all baudrates for the UARTs */ +#if 0 do_fixup_by_compat_u32(blob, "ns16550", "clock-frequency", gd->uart_clk, 1); +#endif + start = fdt_path_offset(blob, "/plb/opb"); + stop = ft_path_end_offset(blob, "/plb/opb"); + printf("/plb/opb start=%d, stop=%d\n", start, stop); + + start2 = fdt_path_offset(blob, "/plb/opb/ebc"); + stop2 = ft_path_end_offset(blob, "/plb/opb/ebc"); + printf("/plb/opb/obc start=%d, stop=%d\n", start, stop); + + off = start; + while (off != -FDT_ERR_NOTFOUND) { + off = fdt_node_offset_by_compatible(blob, off, "ns16550"); + printf("off=%d\n", off); + if ((off > start) && (off < stop)) { + if ((start2 < 0) || (off < start2) || (off > stop2)) { + printf("ns16550 directly on OPB\n"); + if (fdt_get_property(blob, off, + "clock-frequency", + 0) != NULL) + fdt_setprop(blob, off, + "clock-frequency", + (void*)&(gd->uart_clk), 4); + } + } + }
/* * Fixup all ethernet nodes