2 * Copyright 2014, Ithamar R. Adema <ithamar@upgrade-android.com>
3 * All rights reserved. Distributed under the terms of the MIT License.
6 #include <drivers/bus/FDT.h>
7 #include <KernelExport.h>
8 #include <util/kernel_cpp.h>
10 #include <ctype.h> // isprint
11 #include <stdio.h> // snprintf
16 #include <libfdt_env.h>
21 static status_t
fdt_setup_devices(struct fdt_device_info
*info
, int count
, void *cookie
);
23 static const char *sTabTab
= "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
25 #define DA depth - 1, sTabTab
28 fdt_dump_value(const char *data
, int32 len
, int depth
)
36 for (i
= 0; i
< len
; ) {
39 for (; i
< len
&& (p
== str
|| (i
% 16 != 0)); i
++) {
40 snprintf(p
, l
- 1, "%02x ", data
[i
]);
43 astr
[i
% 16] = isprint(data
[i
]) ? data
[i
] : '.';
44 astr
[i
% 16] = isprint(data
[i
]) ? data
[i
] : '.';
45 astr
[(i
% 16) + 1] = '\0';
47 dprintf(DS
" %-48.48s %s\n", DA
, str
, astr
);
52 fdt_debug_tree(int argc
, char **argv
)
54 bool dump_props
= false, dump_values
= false;
57 dprintf("No fdt tree\n");
61 dprintf("fdt tree:\n");
65 while ((node
= fdt_next_node(gFDT
, node
, &depth
)) >= 0) {
66 dprintf(DS
"node at %d: '%s'\n", DA
, node
,
67 fdt_get_name(gFDT
, node
, NULL
));
71 const struct fdt_property
*property
;
72 prop
= fdt_first_property_offset(gFDT
, node
);
74 property
= fdt_get_property_by_offset(gFDT
, prop
, &len
);
75 if (property
== NULL
) {
76 dprintf("getting prop at %d: %s\n", prop
, fdt_strerror(len
));
79 dprintf(DS
" prop at %d: '%s', len %d\n", DA
, prop
,
80 fdt_string(gFDT
, fdt32_to_cpu(property
->nameoff
)),
81 fdt32_to_cpu(property
->len
));
84 fdt_dump_value(property
->data
, fdt32_to_cpu(property
->len
), depth
);
86 prop
= fdt_next_property_offset(gFDT
, prop
);
96 bus_std_ops(int32 op
, ...)
100 if (gFDT
== NULL
|| fdt_totalsize(gFDT
) <= 0)
103 add_debugger_command("fdt", &fdt_debug_tree
, "Show Flattened Device Tree");
106 case B_MODULE_UNINIT
:
107 // Nothing to free, gFDT allocation is managed by kernel
118 fdt_get_interrupt(fdt_device_node node
, int index
)
120 const struct fdt_property
*prop
;
123 prop
= fdt_get_property(gFDT
, node
, "interrupts", &lenp
);
125 return B_NAME_NOT_FOUND
;
127 int numRanges
= lenp
/ sizeof(uint32
);
128 if (index
> numRanges
)
131 return fdt32_to_cpu(((uint32
*)prop
->data
)[index
]);
135 fdt_map_reg_range(fdt_device_node node
, int index
, void **_address
)
137 char name
[B_OS_NAME_LENGTH
] = "ingo_asked_me_to_name_this";
138 const struct fdt_property
*prop
;
141 prop
= fdt_get_property(gFDT
, node
, "reg", &lenp
);
143 return B_NAME_NOT_FOUND
;
145 int numRanges
= lenp
/ (sizeof(uint32
) * 2);
146 if (index
> numRanges
)
149 //snprintf(name, sizeof(name), "%s_reg_%d", fdt_get_name(gFDT, node, NULL), index);
151 uint32
* regs
= (uint32
*)prop
->data
;
152 phys_addr_t rangeStart
= (phys_addr_t
)fdt32_to_cpu(regs
[index
*2]);
153 uint32 rangeSize
= fdt32_to_cpu(regs
[index
*2+1]);
154 dprintf("fdt_map_reg_range: found reg range %p/%lu\n", (void*)rangeStart
, rangeSize
);
156 return map_physical_memory(name
, rangeStart
, rangeSize
,
157 0, B_KERNEL_READ_AREA
| B_KERNEL_WRITE_AREA
, (void**)_address
);
160 static struct fdt_module_info sModuleInfo
= {
161 // First the bus_manager_info:
164 "bus_managers/fdt/v1",
165 B_KEEP_LOADED
, // Keep loaded, even if no driver requires it
168 NULL
// the rescan function
177 module_info
*modules
[] = {
178 (module_info
*)&sModuleInfo
,
183 fdt_setup_devices(struct fdt_device_info
*info
, int count
, void *cookie
)
188 return B_NOT_INITIALIZED
;
192 while ((node
= fdt_next_node(gFDT
, node
, &depth
)) >= 0) {
193 for (int i
=0; i
< count
; i
++) {
194 if (fdt_node_check_compatible(gFDT
, node
, info
[i
].compatible
) == 0) {
195 status_t result
= info
[i
].init(&sModuleInfo
, node
, cookie
);
196 if (result
!= B_OK
) {
197 // TODO handle return value from init somehow?
198 dprintf("fdt: device '%s' failed to initialize!\n",
199 fdt_get_name(gFDT
, node
, NULL
));
207 return (numDevs
<= 0) ? B_ENTRY_NOT_FOUND
: B_OK
;