fdt: Add fdt_translate_address to convert reg node to cpu phys addr
PATCH 1/2 fdt: Add fdt_translate_address to convert reg node to cpu phys addr
This code is extracted out of the Linux Kernel code from arch/powerpc/kernel/prom_parse.c.
We maintain some of the same structure to support multiple bus types even though we only have one in the current code. In the future we might want to translate across a PCI bus and thus it will be easier to add that functionality back in.
--- common/fdt_support.c | 264 +++++++++++++++++++++++++++++++++++++++++++++++++ include/fdt_support.h | 1 + 2 files changed, 265 insertions(+), 0 deletions(-)
common/fdt_support.c +264 -0
@@ -2,6 +2,8 @@* (C) Copyright 2007 * Gerald Van Baren, Custom IDEAS, vanbaren at cideas.com * +* Copyright 2010 Freescale Semiconductor, Inc. +* * See file CREDITS for list of people who contributed to this * project. *
@@ -861,3 +863,265 @@ void fdt_del_node_and_alias(void *blob, const char *alias) off =fdt_path_offset (blob,"/aliases" );fdt_delprop (blob, off, alias); } + +/* Helper to read a big number; size is in cells (not bytes) */ +static inline u64 of_read_number (const __be32 *cell,int size) +{ +u64 r =0 ; +while (size--) + r = (r <<32 ) |be32_to_cpu (*(cell++)); +return r; +} + +static int of_n_cells (const void *blob,int nodeoffset,const char *name) +{ +int np; +const int *ip; + +do { + np =fdt_parent_offset (blob, nodeoffset); + +if (np >=0 ) + nodeoffset = np; + ip = (int *)fdt_getprop (blob, nodeoffset, name,NULL ); +if (ip) +return be32_to_cpup (ip); + }while (np >=0 ); + +/* No #<NAME>-cells property for the root node */ +return 1 ; +} + +int of_n_addr_cells (const void *blob,int nodeoffset) +{ +return of_n_cells (blob, nodeoffset,"#address-cells" ); +} + +int of_n_size_cells (const void *blob,int nodeoffset) +{ +return of_n_cells (blob, nodeoffset,"#size-cells" ); +} + +#define PRu64 "%llx" + +/* Max address size we deal with */ +#define OF_MAX_ADDR_CELLS 4 +#define OF_BAD_ADDR ((u64)-1) +#define OF_CHECK_COUNTS (na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \ + (ns) > 0) + +/* Debug utility */ +#ifdef DEBUG +static void of_dump_addr (const char *s,const u32 *addr,int na) +{ +printf ("%s" , s); +while (na--) +printf (" %08x" , *(addr++)); +printf ("\n" ); +} +#else +static void of_dump_addr (const char *s,const u32 *addr,int na) { } +#endif + +/* Callbacks for bus specific translators */ +struct of_bus { +const char *name; +const char *addresses; +void (*count_cells)(void *blob,int offset, +int *addrc,int *sizec); +u64 (*map)(u32 *addr,const u32 *range, +int na,int ns,int pna); +int (*translate)(u32 *addr,u64 offset,int na); +}; + +/* Default translator (generic bus) */ +static void of_bus_default_count_cells (void *blob,int offset, +int *addrc,int *sizec) +{ +if (addrc) + *addrc =of_n_addr_cells (blob, offset); +if (sizec) + *sizec =of_n_size_cells (blob, offset); +} + +static u64 of_bus_default_map (u32 *addr,const u32 *range, +int na,int ns,int pna) +{ +u64 cp, s, da; + + cp =of_read_number (range, na); + s =of_read_number (range + na + pna, ns); + da =of_read_number (addr, na); + +debug ("OF: default map, cp=" PRu64", s=" PRu64", da=" PRu64"\n" , + cp, s, da); + +if (da < cp || da >= (cp + s)) +return OF_BAD_ADDR ; +return da - cp; +} + +static int of_bus_default_translate (u32 *addr,u64 offset,int na) +{ +u64 a =of_read_number (addr, na); +memset (addr,0 , na *4 ); + a += offset; +if (na >1 ) + addr[na -2 ] = a >>32 ; + addr[na -1 ] = a &0xffffffffu ; + +return 0 ; +} + +/* Array of bus specific translators */ +static struct of_bus of_busses[] = { +/* Default */ + { + .name ="default" , + .addresses ="reg" , + .count_cells = of_bus_default_count_cells, + .map = of_bus_default_map, + .translate = of_bus_default_translate, + }, +}; + +static int of_translate_one (void * blob,int parent,struct of_bus *bus, +struct of_bus *pbus,u32 *addr, +int na,int ns,int pna,const char *rprop) +{ +const u32 *ranges; +int rlen; +int rone; +u64 offset =OF_BAD_ADDR ; + +/* Normally, an absence of a "ranges" property means we are +* crossing a non-translatable boundary, and thus the addresses +* below the current not cannot be converted to CPU physical ones. +* Unfortunately, while this is very clear in the spec, it's not +* what Apple understood, and they do have things like /uni-n or +* /ht nodes with no "ranges" property and a lot of perfectly +* useable mapped devices below them. Thus we treat the absence of +* "ranges" as equivalent to an empty "ranges" property which means +* a 1:1 translation at that level. It's up to the caller not to try +* to translate addresses that aren't supposed to be translated in +* the first place. --BenH. +*/ + ranges = (u32 *)fdt_getprop (blob, parent, rprop, &rlen); +if (ranges ==NULL || rlen ==0 ) { + offset =of_read_number (addr, na); +memset (addr,0 , pna *4 ); +debug ("OF: no ranges, 1:1 translation\n" ); + goto finish; + } + +debug ("OF: walking ranges...\n" ); + +/* Now walk through the ranges */ + rlen /=4 ; + rone = na + pna + ns; +for (; rlen >= rone; rlen -= rone, ranges += rone) { + offset = bus->map (addr, ranges, na, ns, pna); +if (offset !=OF_BAD_ADDR ) +break ; + } +if (offset ==OF_BAD_ADDR ) { +debug ("OF: not found !\n" ); +return 1 ; + } +memcpy (addr, ranges + na,4 * pna); + + finish: +of_dump_addr ("OF: parent translation for:" , addr, pna); +debug ("OF: with offset: " PRu64"\n" , offset); + +/* Translate it into parent bus space */ +return pbus->translate (addr, offset, pna); +} + +/* +* Translate an address from the device-tree into a CPU physical address, +* this walks up the tree and applies the various bus mappings on the +* way. +* +* Note: We consider that crossing any level with #size-cells == 0 to mean +* that translation is impossible (that is we are not dealing with a value +* that can be mapped to a cpu physical address). This is not really specified +* that way, but this is traditionally the way IBM at least do things +*/ +u64 __of_translate_address (void *blob,int node_offset,const u32 *in_addr, +const char *rprop) +{ +int parent; +struct of_bus *bus, *pbus; +u32 addr[OF_MAX_ADDR_CELLS ]; +int na, ns, pna, pns; +u64 result =OF_BAD_ADDR ; + +debug ("OF: ** translation for device %s **\n" , +fdt_get_name (blob, node_offset,NULL )); + +/* Get parent & match bus type */ + parent =fdt_parent_offset (blob, node_offset); +if (parent <0 ) + goto bail; + bus = &of_busses[0 ]; + +/* Cound address cells & copy address locally */ + bus->count_cells (blob, node_offset, &na, &ns); +if (!OF_CHECK_COUNTS (na, ns)) { +printf ("%s: Bad cell count for %s\n" , __FUNCTION__, +fdt_get_name (blob, node_offset,NULL )); + goto bail; + } +memcpy (addr, in_addr, na *4 ); + +debug ("OF: bus is %s (na=%d, ns=%d) on %s\n" , + bus->name, na, ns,fdt_get_name (blob, parent,NULL )); +of_dump_addr ("OF: translating address:" , addr, na); + +/* Translate */ +for (;;) { +/* Switch to parent bus */ + node_offset = parent; + parent =fdt_parent_offset (blob, node_offset); + +/* If root, we have finished */ +if (parent <0 ) { +debug ("OF: reached root node\n" ); + result =of_read_number (addr, na); +break ; + } + +/* Get new parent bus and counts */ + pbus = &of_busses[0 ]; + pbus->count_cells (blob, node_offset, &pna, &pns); +if (!OF_CHECK_COUNTS (pna, pns)) { +printf ("%s: Bad cell count for %s\n" , __FUNCTION__, +fdt_get_name (blob, node_offset,NULL )); +break ; + } + +debug ("OF: parent bus is %s (na=%d, ns=%d) on %s\n" , + pbus->name, pna, pns,fdt_get_name (blob, parent,NULL )); + +/* Apply bus translation */ +if (of_translate_one (blob, node_offset, bus, pbus, + addr, na, ns, pna, rprop)) +break ; + +/* Complete the move up one level */ + na = pna; + ns = pns; + bus = pbus; + +of_dump_addr ("OF: one level translation:" , addr, na); + } + bail: + +return result; +} + +u64 fdt_translate_address (void *blob,int node_offset,const u32 *in_addr) +{ +return __of_translate_address (blob, node_offset, in_addr,"ranges" ); +}
include/fdt_support.h +1 -0
@@ -83,6 +83,7 @@ int fdt_fixup_nor_flash_size(void *blob, int cs, u32 size);void fdt_fixup_mtdparts (void *fdt,void *node_info,int node_info_size);void fdt_del_node_and_alias (void *blob,const char *alias); +u64 fdt_translate_address (void *blob,int node_offset,const u32 *in_addr);#endif /* ifdef CONFIG_OF_LIBFDT */ #endif /* ifndef __FDT_SUPPORT_H */
Signature · 1 line
1.6.0.6
PATCH 1/2 fdt: Add fdt_translate_address to convert reg node to cpu phys addr
Quoted 8 lines · Kumar Gala
This code is extracted out of the Linux Kernel code from
arch/powerpc/kernel/prom_parse.c.We maintain some of the same structure to support multiple bus types even though we only have one in the current code. In the future we might want to translate across a PCI bus and thus it will be easier to add that functionality back in.
Quoted 5 lines
Signed-off-by Kumar Gala <[email protected]>---
common/fdt_support.c| 264 +++++++++++++++++++++++++++++++++++++++++++++++++include/fdt_support.h| 1 +2 files changed, 265 insertions(+), 0 deletions(-)
Jerry,
Any comments?
- k
PATCH 1/2 fdt: Add fdt_translate_address to convert reg node to cpu phys addr
Hi Kumar,
Quoted 17 lines · Kumar Gala
Quoted 8 lines · Kumar Gala
This code is extracted out of the Linux Kernel code from
arch/powerpc/kernel/prom_parse.c.We maintain some of the same structure to support multiple bus types even though we only have one in the current code. In the future we might want to translate across a PCI bus and thus it will be easier to add that functionality back in.
Quoted 5 lines
Signed-off-by Kumar Gala<[email protected]>---
common/fdt_support.c| 264 +++++++++++++++++++++++++++++++++++++++++++++++++include/fdt_support.h| 1 +2 files changed, 265 insertions(+), 0 deletions(-)
Quoted 5 lines
Jerry,
Any comments?
- k
Looks OK to me.
gvb
Kumar Gala
AppliedPATCH 1/2 fdt: Add fdt_translate_address to convert reg node to cpu phys addr
Quoted 24 lines · Jerry Van Baren
Hi Kumar,
Quoted 21 lines · Kumar Gala
Quoted 8 lines · Kumar Gala
This code is extracted out of the Linux Kernel code from
arch/powerpc/kernel/prom_parse.c.We maintain some of the same structure to support multiple bus types even though we only have one in the current code. In the future we might want to translate across a PCI bus and thus it will be easier to add that functionality back in.
Quoted 5 lines
Signed-off-by Kumar Gala<[email protected]>---
common/fdt_support.c| 264 +++++++++++++++++++++++++++++++++++++++++++++++++include/fdt_support.h| 1 +2 files changed, 265 insertions(+), 0 deletions(-)Jerry,
Any comments?
Quoted 8 lines
Quoted 1 line
- k
Looks OK to me.
Acked-by Gerald Van Baren <[email protected]>gvb
applied to 85xx
- k
PATCH 2/2 fdt: Add fdt_node_offset_by_compat_reg helper
In reply to Kumar GalaGiven a compatiable string and physical address try and find a node that matches. This is useful when we want to find a specific device node to update (for example if we have multiple PCI nodes we can use the physical address to distinquish them when trying to update the device tree).
--- common/fdt_support.c | 27 +++++++++++++++++++++++++++ include/fdt_support.h | 2 ++ 2 files changed, 29 insertions(+), 0 deletions(-)
common/fdt_support.c +27 -0
@@ -1125,3 +1125,30 @@ u64 fdt_translate_address(void *blob, int node_offset, const u32 *in_addr) {return __of_translate_address (blob, node_offset, in_addr,"ranges" ); } + +/** +* fdt_node_offset_by_compat_reg: Find a node that matches compatiable and +* who's reg property matches a physical cpu address +* +* @blob: ptr to device tree +* @compat: compatiable string to match +* @compat_off: property name +* +*/ +int fdt_node_offset_by_compat_reg (void *blob,const char *compat, +phys_addr_t compat_off) +{ +int len, off =fdt_node_offset_by_compatible (blob,-1 , compat); +while (off != -FDT_ERR_NOTFOUND ) { +u32 *reg = (u32 *)fdt_getprop (blob, off,"reg" , &len); +if (reg) { +if (compat_off ==fdt_translate_address (blob, off, reg)) +return off; + } + off =fdt_node_offset_by_compatible (blob, off, compat); + } + +return -FDT_ERR_NOTFOUND ; +} + +
include/fdt_support.h +2 -0
@@ -84,6 +84,8 @@ int fdt_fixup_nor_flash_size(void *blob, int cs, u32 size);void fdt_fixup_mtdparts (void *fdt,void *node_info,int node_info_size);void fdt_del_node_and_alias (void *blob,const char *alias);u64 fdt_translate_address (void *blob,int node_offset,const u32 *in_addr); +int fdt_node_offset_by_compat_reg (void *blob,const char *compat, +phys_addr_t compat_off);#endif /* ifdef CONFIG_OF_LIBFDT */ #endif /* ifndef __FDT_SUPPORT_H */
Signature · 1 line
1.6.0.6
PATCH 2/2 fdt: Add fdt_node_offset_by_compat_reg helper
Quoted 11 lines · Kumar Gala
Given a compatiable string and physical address try and find a node that matches. This is useful when we want to find a specific device node to update (for example if we have multiple PCI nodes we can use the physical address to distinquish them when trying to update the device tree).
Signed-off-by Kumar Gala <[email protected]>---
common/fdt_support.c| 27 +++++++++++++++++++++++++++include/fdt_support.h| 2 ++2 files changed, 29 insertions(+), 0 deletions(-)
Jerry,
Any comments?
- k
PATCH 2/2 fdt: Add fdt_node_offset_by_compat_reg helper
Hi Kumar,
Quoted 4 lines · Kumar Gala
Quoted 1 line · Kumar Gala
Given a compatiable string and physical address try and find a node that
compatible
Quoted 3 lines
Quoted 3 lines
matches. This is useful when we want to find a specific device node to update (for example if we have multiple PCI nodes we can use the physical address to distinquish them when trying to update the device
distinguish (s/q/g/)
Quoted 3 lines
Quoted 3 lines
tree).
Signed-off-by Kumar Gala<[email protected]>
^
Probably should have a space in your signed-off-by line just in case a SOB line parser is picky.
Quoted 10 lines
Quoted 4 lines
---
common/fdt_support.c| 27 +++++++++++++++++++++++++++include/fdt_support.h| 2 ++2 files changed, 29 insertions(+), 0 deletions(-)Jerry,
Any comments?
- k
Looks OK to me other than two typos in the comment.
gvb
PATCH 2/2 fdt: Add fdt_node_offset_by_compat_reg helper
Quoted 31 lines · Jerry Van Baren
Hi Kumar,
Quoted 4 lines · Kumar Gala
Quoted 1 line · Kumar Gala
Given a compatiable string and physical address try and find a node that
compatible
Quoted 3 lines
Quoted 3 lines
matches. This is useful when we want to find a specific device node to update (for example if we have multiple PCI nodes we can use the physical address to distinquish them when trying to update the device
distinguish (s/q/g/)
Quoted 3 lines
Quoted 3 lines
tree).
Signed-off-by Kumar Gala<[email protected]>^Probably should have a space in your signed-off-by line just in case a SOB line parser is picky.
Quoted 9 lines
Quoted 4 lines
---
common/fdt_support.c| 27 +++++++++++++++++++++++++++include/fdt_support.h| 2 ++2 files changed, 29 insertions(+), 0 deletions(-)Jerry,
Any comments?
Quoted 7 lines
Quoted 1 line
- k
Looks OK to me other than two typos in the comment.
Acked-by Gerald Van Baren <[email protected]>gvb
applied with commit comment fixes
- k