1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * (C) Copyright 2018 Linaro Ltd.
3*4882a593Smuzhiyun * Sam Protsenko <semen.protsenko@linaro.org>
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <image-android-dt.h>
9*4882a593Smuzhiyun #include <dt_table.h>
10*4882a593Smuzhiyun #include <common.h>
11*4882a593Smuzhiyun #include <linux/libfdt.h>
12*4882a593Smuzhiyun #include <mapmem.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun /**
15*4882a593Smuzhiyun * Check if image header is correct.
16*4882a593Smuzhiyun *
17*4882a593Smuzhiyun * @param hdr_addr Start address of DT image
18*4882a593Smuzhiyun * @return true if header is correct or false if header is incorrect
19*4882a593Smuzhiyun */
android_dt_check_header(ulong hdr_addr)20*4882a593Smuzhiyun bool android_dt_check_header(ulong hdr_addr)
21*4882a593Smuzhiyun {
22*4882a593Smuzhiyun const struct dt_table_header *hdr;
23*4882a593Smuzhiyun u32 magic;
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun hdr = map_sysmem(hdr_addr, sizeof(*hdr));
26*4882a593Smuzhiyun magic = fdt32_to_cpu(hdr->magic);
27*4882a593Smuzhiyun unmap_sysmem(hdr);
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun return magic == DT_TABLE_MAGIC;
30*4882a593Smuzhiyun }
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun /**
33*4882a593Smuzhiyun * Get the address of FDT (dtb or dtbo) in memory by its index in image.
34*4882a593Smuzhiyun *
35*4882a593Smuzhiyun * @param hdr_addr Start address of DT image
36*4882a593Smuzhiyun * @param index Index of desired FDT in image (starting from 0)
37*4882a593Smuzhiyun * @param[out] addr If not NULL, will contain address to specified FDT
38*4882a593Smuzhiyun * @param[out] size If not NULL, will contain size of specified FDT
39*4882a593Smuzhiyun *
40*4882a593Smuzhiyun * @return true on success or false on error
41*4882a593Smuzhiyun */
android_dt_get_fdt_by_index(ulong hdr_addr,u32 index,ulong * addr,u32 * size)42*4882a593Smuzhiyun bool android_dt_get_fdt_by_index(ulong hdr_addr, u32 index, ulong *addr,
43*4882a593Smuzhiyun u32 *size)
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun const struct dt_table_header *hdr;
46*4882a593Smuzhiyun const struct dt_table_entry *e;
47*4882a593Smuzhiyun u32 entry_count, entries_offset, entry_size;
48*4882a593Smuzhiyun ulong e_addr;
49*4882a593Smuzhiyun u32 dt_offset, dt_size;
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun hdr = map_sysmem(hdr_addr, sizeof(*hdr));
52*4882a593Smuzhiyun entry_count = fdt32_to_cpu(hdr->dt_entry_count);
53*4882a593Smuzhiyun entries_offset = fdt32_to_cpu(hdr->dt_entries_offset);
54*4882a593Smuzhiyun entry_size = fdt32_to_cpu(hdr->dt_entry_size);
55*4882a593Smuzhiyun unmap_sysmem(hdr);
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun if (index > entry_count) {
58*4882a593Smuzhiyun printf("Error: index > dt_entry_count (%u > %u)\n", index,
59*4882a593Smuzhiyun entry_count);
60*4882a593Smuzhiyun return false;
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun e_addr = hdr_addr + entries_offset + index * entry_size;
64*4882a593Smuzhiyun e = map_sysmem(e_addr, sizeof(*e));
65*4882a593Smuzhiyun dt_offset = fdt32_to_cpu(e->dt_offset);
66*4882a593Smuzhiyun dt_size = fdt32_to_cpu(e->dt_size);
67*4882a593Smuzhiyun unmap_sysmem(e);
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun if (addr)
70*4882a593Smuzhiyun *addr = hdr_addr + dt_offset;
71*4882a593Smuzhiyun if (size)
72*4882a593Smuzhiyun *size = dt_size;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun return true;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun #if !defined(CONFIG_SPL_BUILD)
android_dt_print_fdt_info(const struct fdt_header * fdt)78*4882a593Smuzhiyun static void android_dt_print_fdt_info(const struct fdt_header *fdt)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun u32 fdt_size;
81*4882a593Smuzhiyun int root_node_off;
82*4882a593Smuzhiyun const char *compatible = NULL;
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun fdt_size = fdt_totalsize(fdt);
85*4882a593Smuzhiyun root_node_off = fdt_path_offset(fdt, "/");
86*4882a593Smuzhiyun if (root_node_off < 0) {
87*4882a593Smuzhiyun printf("Error: Root node not found\n");
88*4882a593Smuzhiyun } else {
89*4882a593Smuzhiyun compatible = fdt_getprop(fdt, root_node_off, "compatible",
90*4882a593Smuzhiyun NULL);
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun printf(" (FDT)size = %d\n", fdt_size);
94*4882a593Smuzhiyun printf(" (FDT)compatible = %s\n",
95*4882a593Smuzhiyun compatible ? compatible : "(unknown)");
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun /**
99*4882a593Smuzhiyun * Print information about DT image structure.
100*4882a593Smuzhiyun *
101*4882a593Smuzhiyun * @param hdr_addr Start address of DT image
102*4882a593Smuzhiyun */
android_dt_print_contents(ulong hdr_addr)103*4882a593Smuzhiyun void android_dt_print_contents(ulong hdr_addr)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun const struct dt_table_header *hdr;
106*4882a593Smuzhiyun u32 entry_count, entries_offset, entry_size;
107*4882a593Smuzhiyun u32 i;
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun hdr = map_sysmem(hdr_addr, sizeof(*hdr));
110*4882a593Smuzhiyun entry_count = fdt32_to_cpu(hdr->dt_entry_count);
111*4882a593Smuzhiyun entries_offset = fdt32_to_cpu(hdr->dt_entries_offset);
112*4882a593Smuzhiyun entry_size = fdt32_to_cpu(hdr->dt_entry_size);
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun /* Print image header info */
115*4882a593Smuzhiyun printf("dt_table_header:\n");
116*4882a593Smuzhiyun printf(" magic = %08x\n", fdt32_to_cpu(hdr->magic));
117*4882a593Smuzhiyun printf(" total_size = %d\n", fdt32_to_cpu(hdr->total_size));
118*4882a593Smuzhiyun printf(" header_size = %d\n", fdt32_to_cpu(hdr->header_size));
119*4882a593Smuzhiyun printf(" dt_entry_size = %d\n", entry_size);
120*4882a593Smuzhiyun printf(" dt_entry_count = %d\n", entry_count);
121*4882a593Smuzhiyun printf(" dt_entries_offset = %d\n", entries_offset);
122*4882a593Smuzhiyun printf(" page_size = %d\n", fdt32_to_cpu(hdr->page_size));
123*4882a593Smuzhiyun printf(" version = %08x\n", fdt32_to_cpu(hdr->version));
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun unmap_sysmem(hdr);
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun /* Print image entries info */
128*4882a593Smuzhiyun for (i = 0; i < entry_count; ++i) {
129*4882a593Smuzhiyun const ulong e_addr = hdr_addr + entries_offset + i * entry_size;
130*4882a593Smuzhiyun const struct dt_table_entry *e;
131*4882a593Smuzhiyun const struct fdt_header *fdt;
132*4882a593Smuzhiyun u32 dt_offset, dt_size;
133*4882a593Smuzhiyun u32 j;
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun e = map_sysmem(e_addr, sizeof(*e));
136*4882a593Smuzhiyun dt_offset = fdt32_to_cpu(e->dt_offset);
137*4882a593Smuzhiyun dt_size = fdt32_to_cpu(e->dt_size);
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun printf("dt_table_entry[%d]:\n", i);
140*4882a593Smuzhiyun printf(" dt_size = %d\n", dt_size);
141*4882a593Smuzhiyun printf(" dt_offset = %d\n", dt_offset);
142*4882a593Smuzhiyun printf(" id = %08x\n", fdt32_to_cpu(e->id));
143*4882a593Smuzhiyun printf(" rev = %08x\n", fdt32_to_cpu(e->rev));
144*4882a593Smuzhiyun for (j = 0; j < 4; ++j) {
145*4882a593Smuzhiyun printf(" custom[%d] = %08x\n", j,
146*4882a593Smuzhiyun fdt32_to_cpu(e->custom[j]));
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun unmap_sysmem(e);
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun /* Print FDT info for this entry */
152*4882a593Smuzhiyun fdt = map_sysmem(hdr_addr + dt_offset, sizeof(*fdt));
153*4882a593Smuzhiyun android_dt_print_fdt_info(fdt);
154*4882a593Smuzhiyun unmap_sysmem(fdt);
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun #endif
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun /**
160*4882a593Smuzhiyun * Get dt entry count of DT image structure.
161*4882a593Smuzhiyun *
162*4882a593Smuzhiyun * @param hdr_addr Start address of DT image
163*4882a593Smuzhiyun */
android_dt_get_count(ulong hdr_addr)164*4882a593Smuzhiyun int android_dt_get_count(ulong hdr_addr)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun const struct dt_table_header *hdr;
167*4882a593Smuzhiyun int count;
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun hdr = map_sysmem(hdr_addr, sizeof(*hdr));
170*4882a593Smuzhiyun count = fdt32_to_cpu(hdr->dt_entry_count);
171*4882a593Smuzhiyun unmap_sysmem(hdr);
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun return count;
174*4882a593Smuzhiyun }
175