blob: 40c24a4bc7c0bd29039e369148649ead90f21064 [file] [log] [blame]
David Ng59c4a782015-05-14 15:51:44 -07001/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27*/
28
29#include <libfdt.h>
30#include <dev_tree.h>
31#include <lib/ptable.h>
32#include <malloc.h>
33#include <qpic_nand.h>
34#include <stdlib.h>
35#include <string.h>
36#include <platform.h>
37#include <board.h>
Lijuan Gao9f152862014-08-18 13:45:24 +080038#include <list.h>
39#include <kernel/thread.h>
vijay kumar4f4405f2014-08-08 11:49:53 +053040#include <target.h>
Channagoud Kadabiffaea422014-12-05 15:45:41 -080041#include <partial_goods.h>
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -070042
Joel Kingaa335dc2013-06-03 16:11:08 -070043struct dt_entry_v1
44{
45 uint32_t platform_id;
46 uint32_t variant_id;
47 uint32_t soc_rev;
48 uint32_t offset;
49 uint32_t size;
50};
51
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -070052static struct dt_mem_node_info mem_node;
Lijuan Gao9f152862014-08-18 13:45:24 +080053static int platform_dt_absolute_match(struct dt_entry *cur_dt_entry, struct dt_entry_node *dt_list);
54static struct dt_entry *platform_dt_match_best(struct dt_entry_node *dt_list);
55static int update_dtb_entry_node(struct dt_entry_node *dt_list, uint32_t dtb_info);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -070056extern int target_is_emmc_boot(void);
57extern uint32_t target_dev_tree_mem(void *fdt, uint32_t memory_node_offset);
Deepa Dinamanic55f01b2013-05-30 14:05:56 -070058/* TODO: This function needs to be moved to target layer to check violations
59 * against all the other regions as well.
60 */
61extern int check_aboot_addr_range_overlap(uint32_t start, uint32_t size);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -070062
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +053063int fdt_check_header_ext(const void *fdt)
64{
65 uintptr_t fdt_start, fdt_end;
66 fdt_start = (uintptr_t)fdt;
67 if(fdt_start + fdt_totalsize(fdt) < fdt_start)
68 {
69 dprintf(CRITICAL,"Integer over in fdt header %s\t%d",__func__,__LINE__);
70 return FDT_ERR_BADOFFSET;
71 }
72 fdt_end = fdt_start + fdt_totalsize(fdt);
73
74 if (((uint64_t)fdt_start + (uint64_t)fdt_off_dt_struct(fdt) + (uint64_t)fdt_size_dt_struct(fdt)) > UINT_MAX)
75 return FDT_ERR_BADOFFSET;
76
77 if ((fdt_start + fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt)) > fdt_end)
78 return FDT_ERR_BADOFFSET;
79
80 if (((uint64_t)fdt_start + (uint64_t)fdt_off_dt_strings(fdt) + (uint64_t)fdt_size_dt_strings(fdt)) > UINT_MAX)
81 return FDT_ERR_BADOFFSET;
82
83 if ((fdt_start + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)) > fdt_end)
84 return FDT_ERR_BADOFFSET;
85
86 return 0;
87}
88
Shashank Mittalc0f10282013-07-15 14:53:31 -070089/* Returns soc version if platform id and hardware id matches
90 otherwise return 0xFFFFFFFF */
91#define INVALID_SOC_REV_ID 0XFFFFFFFF
Lijuan Gao9f152862014-08-18 13:45:24 +080092
93/* Add function to allocate dt entry list, used for recording
94* the entry which conform to platform_dt_absolute_match()
95*/
96static struct dt_entry_node *dt_entry_list_init(void)
97{
98 struct dt_entry_node *dt_node_member = NULL;
99
100 dt_node_member = (struct dt_entry_node *)
101 malloc(sizeof(struct dt_entry_node));
102
103 ASSERT(dt_node_member);
104
105 list_clear_node(&dt_node_member->node);
106 dt_node_member->dt_entry_m = (struct dt_entry *)
107 malloc(sizeof(struct dt_entry));
108 ASSERT(dt_node_member->dt_entry_m);
109
110 memset(dt_node_member->dt_entry_m ,0 ,sizeof(struct dt_entry));
111 return dt_node_member;
112}
113
114static void insert_dt_entry_in_queue(struct dt_entry_node *dt_list, struct dt_entry_node *dt_node_member)
115{
116 list_add_tail(&dt_list->node, &dt_node_member->node);
117}
118
119static void dt_entry_list_delete(struct dt_entry_node *dt_node_member)
120{
121 if (list_in_list(&dt_node_member->node)) {
122 list_delete(&dt_node_member->node);
123 free(dt_node_member->dt_entry_m);
124 free(dt_node_member);
125 }
126}
127
128static int dev_tree_compatible(void *dtb, uint32_t dtb_size, struct dt_entry_node *dtb_list)
Dima Zavinc46f8382013-05-03 12:23:06 -0700129{
130 int root_offset;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700131 const void *prop = NULL;
132 const char *plat_prop = NULL;
133 const char *board_prop = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800134 const char *pmic_prop = NULL;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700135 char *model = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800136 struct dt_entry *cur_dt_entry;
137 struct dt_entry *dt_entry_array = NULL;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700138 struct board_id *board_data = NULL;
139 struct plat_id *platform_data = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800140 struct pmic_id *pmic_data = NULL;
Dima Zavinc46f8382013-05-03 12:23:06 -0700141 int len;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700142 int len_board_id;
143 int len_plat_id;
144 int min_plat_id_len = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800145 int len_pmic_id;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700146 uint32_t dtb_ver;
147 uint32_t num_entries = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800148 uint32_t i, j, k, n;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700149 uint32_t msm_data_count;
150 uint32_t board_data_count;
Lijuan Gao9f152862014-08-18 13:45:24 +0800151 uint32_t pmic_data_count;
Dima Zavinc46f8382013-05-03 12:23:06 -0700152
153 root_offset = fdt_path_offset(dtb, "/");
154 if (root_offset < 0)
155 return false;
156
157 prop = fdt_getprop(dtb, root_offset, "model", &len);
158 if (prop && len > 0) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700159 model = (char *) malloc(sizeof(char) * len);
160 ASSERT(model);
161 strlcpy(model, prop, len);
Dima Zavinc46f8382013-05-03 12:23:06 -0700162 } else {
vijay kumar89d36d82014-06-30 19:32:18 +0530163 dprintf(INFO, "model does not exist in device tree\n");
Dima Zavinc46f8382013-05-03 12:23:06 -0700164 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800165 /* Find the pmic-id prop from DTB , if pmic-id is present then
166 * the DTB is version 3, otherwise find the board-id prop from DTB ,
167 * if board-id is present then the DTB is version 2 */
168 pmic_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,pmic-id", &len_pmic_id);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700169 board_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,board-id", &len_board_id);
Lijuan Gao9f152862014-08-18 13:45:24 +0800170 if (pmic_prop && (len_pmic_id > 0) && board_prop && (len_board_id > 0)) {
171 if ((len_pmic_id % PMIC_ID_SIZE) || (len_board_id % BOARD_ID_SIZE))
172 {
173 dprintf(CRITICAL, "qcom,pmic-id(%d) or qcom,board-id(%d) in device tree is not a multiple of (%d %d)\n",
174 len_pmic_id, len_board_id, PMIC_ID_SIZE, BOARD_ID_SIZE);
175 return false;
176 }
177 dtb_ver = DEV_TREE_VERSION_V3;
178 min_plat_id_len = PLAT_ID_SIZE;
179 } else if (board_prop && len_board_id > 0) {
vijay kumar89d36d82014-06-30 19:32:18 +0530180 if (len_board_id % BOARD_ID_SIZE)
181 {
182 dprintf(CRITICAL, "qcom,board-id in device tree is (%d) not a multiple of (%d)\n",
183 len_board_id, BOARD_ID_SIZE);
184 return false;
185 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700186 dtb_ver = DEV_TREE_VERSION_V2;
187 min_plat_id_len = PLAT_ID_SIZE;
Lijuan Gao9f152862014-08-18 13:45:24 +0800188 } else {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700189 dtb_ver = DEV_TREE_VERSION_V1;
190 min_plat_id_len = DT_ENTRY_V1_SIZE;
191 }
192
193 /* Get the msm-id prop from DTB */
194 plat_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,msm-id", &len_plat_id);
195 if (!plat_prop || len_plat_id <= 0) {
Dima Zavinc46f8382013-05-03 12:23:06 -0700196 dprintf(INFO, "qcom,msm-id entry not found\n");
197 return false;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700198 } else if (len_plat_id % min_plat_id_len) {
199 dprintf(INFO, "qcom,msm-id in device tree is (%d) not a multiple of (%d)\n",
200 len_plat_id, min_plat_id_len);
Dima Zavinc46f8382013-05-03 12:23:06 -0700201 return false;
202 }
Dima Zavinc46f8382013-05-03 12:23:06 -0700203
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700204 /*
205 * If DTB version is '1' look for <x y z> pair in the DTB
206 * x: platform_id
207 * y: variant_id
208 * z: SOC rev
209 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800210 if (dtb_ver == DEV_TREE_VERSION_V1) {
211 cur_dt_entry = (struct dt_entry *)
212 malloc(sizeof(struct dt_entry));
Dima Zavinc46f8382013-05-03 12:23:06 -0700213
Lijuan Gao9f152862014-08-18 13:45:24 +0800214 if (!cur_dt_entry) {
215 dprintf(CRITICAL, "Out of memory\n");
216 return false;
217 }
218 memset(cur_dt_entry, 0, sizeof(struct dt_entry));
219
220 while (len_plat_id) {
221 cur_dt_entry->platform_id = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->platform_id);
222 cur_dt_entry->variant_id = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->variant_id);
223 cur_dt_entry->soc_rev = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->soc_rev);
224 cur_dt_entry->board_hw_subtype =
225 fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->variant_id) >> 0x18;
226 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
227 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
228 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
229 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
230 cur_dt_entry->offset = (uint32_t)dtb;
231 cur_dt_entry->size = dtb_size;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700232
233 dprintf(SPEW, "Found an appended flattened device tree (%s - %u %u 0x%x)\n",
Lijuan Gao9f152862014-08-18 13:45:24 +0800234 *model ? model : "unknown",
235 cur_dt_entry->platform_id, cur_dt_entry->variant_id, cur_dt_entry->soc_rev);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700236
Lijuan Gao9f152862014-08-18 13:45:24 +0800237 if (platform_dt_absolute_match(cur_dt_entry, dtb_list)) {
238 dprintf(SPEW, "Device tree exact match the board: <%u %u 0x%x> != <%u %u 0x%x>\n",
239 cur_dt_entry->platform_id,
240 cur_dt_entry->variant_id,
241 cur_dt_entry->soc_rev,
242 board_platform_id(),
243 board_hardware_id(),
244 board_soc_version());
245
246 } else {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700247 dprintf(SPEW, "Device tree's msm_id doesn't match the board: <%u %u 0x%x> != <%u %u 0x%x>\n",
Lijuan Gao9f152862014-08-18 13:45:24 +0800248 cur_dt_entry->platform_id,
249 cur_dt_entry->variant_id,
250 cur_dt_entry->soc_rev,
251 board_platform_id(),
252 board_hardware_id(),
253 board_soc_version());
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700254 plat_prop += DT_ENTRY_V1_SIZE;
255 len_plat_id -= DT_ENTRY_V1_SIZE;
256 continue;
257 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700258 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800259 free(cur_dt_entry);
260
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700261 }
262 /*
Lijuan Gao9f152862014-08-18 13:45:24 +0800263 * If DTB Version is '3' then we have split DTB with board & msm data & pmic
264 * populated saperately in board-id & msm-id & pmic-id prop respectively.
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700265 * Extract the data & prepare a look up table
266 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800267 else if (dtb_ver == DEV_TREE_VERSION_V2 || dtb_ver == DEV_TREE_VERSION_V3) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700268 board_data_count = (len_board_id / BOARD_ID_SIZE);
269 msm_data_count = (len_plat_id / PLAT_ID_SIZE);
Lijuan Gao9f152862014-08-18 13:45:24 +0800270 /* If dtb version is v2.0, the pmic_data_count will be <= 0 */
271 pmic_data_count = (len_pmic_id / PMIC_ID_SIZE);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700272
Lijuan Gao9f152862014-08-18 13:45:24 +0800273 /* If we are using dtb v3.0, then we have split board, msm & pmic data in the DTB
274 * If we are using dtb v2.0, then we have split board & msmdata in the DTB
275 */
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700276 board_data = (struct board_id *) malloc(sizeof(struct board_id) * (len_board_id / BOARD_ID_SIZE));
277 ASSERT(board_data);
278 platform_data = (struct plat_id *) malloc(sizeof(struct plat_id) * (len_plat_id / PLAT_ID_SIZE));
279 ASSERT(platform_data);
Lijuan Gao9f152862014-08-18 13:45:24 +0800280 if (dtb_ver == DEV_TREE_VERSION_V3) {
281 pmic_data = (struct pmic_id *) malloc(sizeof(struct pmic_id) * (len_pmic_id / PMIC_ID_SIZE));
282 ASSERT(pmic_data);
283 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700284 i = 0;
285
286 /* Extract board data from DTB */
Lijuan Gao9f152862014-08-18 13:45:24 +0800287 for(i = 0 ; i < board_data_count; i++) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700288 board_data[i].variant_id = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id);
289 board_data[i].platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->platform_subtype);
Lijuan Gao9f152862014-08-18 13:45:24 +0800290 /* For V2/V3 version of DTBs we have platform version field as part
291 * of variant ID, in such case the subtype will be mentioned as 0x0
292 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
293 * SS -- Subtype
294 * PM -- Platform major version
295 * Pm -- Platform minor version
296 * PH -- Platform hardware CDP/MTP
297 * In such case to make it compatible with LK algorithm move the subtype
298 * from variant_id to subtype field
299 */
300 if (board_data[i].platform_subtype == 0)
301 board_data[i].platform_subtype =
302 fdt32_to_cpu(((struct board_id *)board_prop)->variant_id) >> 0x18;
303
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700304 len_board_id -= sizeof(struct board_id);
305 board_prop += sizeof(struct board_id);
306 }
307
308 /* Extract platform data from DTB */
Lijuan Gao9f152862014-08-18 13:45:24 +0800309 for(i = 0 ; i < msm_data_count; i++) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700310 platform_data[i].platform_id = fdt32_to_cpu(((struct plat_id *)plat_prop)->platform_id);
311 platform_data[i].soc_rev = fdt32_to_cpu(((struct plat_id *)plat_prop)->soc_rev);
312 len_plat_id -= sizeof(struct plat_id);
313 plat_prop += sizeof(struct plat_id);
314 }
315
Lijuan Gao9f152862014-08-18 13:45:24 +0800316 if (dtb_ver == DEV_TREE_VERSION_V3 && pmic_prop) {
317 /* Extract pmic data from DTB */
318 for(i = 0 ; i < pmic_data_count; i++) {
319 pmic_data[i].pmic_version[0]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[0]);
320 pmic_data[i].pmic_version[1]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[1]);
321 pmic_data[i].pmic_version[2]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[2]);
322 pmic_data[i].pmic_version[3]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[3]);
323 len_pmic_id -= sizeof(struct pmic_id);
324 pmic_prop += sizeof(struct pmic_id);
325 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700326
Lijuan Gao9f152862014-08-18 13:45:24 +0800327 /* We need to merge board & platform data into dt entry structure */
328 num_entries = msm_data_count * board_data_count * pmic_data_count;
329 } else {
330 /* We need to merge board & platform data into dt entry structure */
331 num_entries = msm_data_count * board_data_count;
332 }
vijay kumar89d36d82014-06-30 19:32:18 +0530333
Lijuan Gao9f152862014-08-18 13:45:24 +0800334 if ((((uint64_t)msm_data_count * (uint64_t)board_data_count * (uint64_t)pmic_data_count) !=
335 msm_data_count * board_data_count * pmic_data_count) ||
336 (((uint64_t)msm_data_count * (uint64_t)board_data_count) != msm_data_count * board_data_count)) {
337
338 free(board_data);
339 free(platform_data);
340 if (pmic_data)
341 free(pmic_data);
342 if (model)
343 free(model);
344 return false;
345 }
346
347 dt_entry_array = (struct dt_entry*) malloc(sizeof(struct dt_entry) * num_entries);
348 ASSERT(dt_entry_array);
349
350 /* If we have '<X>; <Y>; <Z>' as platform data & '<A>; <B>; <C>' as board data.
351 * Then dt entry should look like
352 * <X ,A >;<X, B>;<X, C>;
353 * <Y ,A >;<Y, B>;<Y, C>;
354 * <Z ,A >;<Z, B>;<Z, C>;
355 */
356 i = 0;
357 k = 0;
358 n = 0;
359 for (i = 0; i < msm_data_count; i++) {
360 for (j = 0; j < board_data_count; j++) {
361 if (dtb_ver == DEV_TREE_VERSION_V3 && pmic_prop) {
362 for (n = 0; n < pmic_data_count; n++) {
363 dt_entry_array[k].platform_id = platform_data[i].platform_id;
364 dt_entry_array[k].soc_rev = platform_data[i].soc_rev;
365 dt_entry_array[k].variant_id = board_data[j].variant_id;
366 dt_entry_array[k].board_hw_subtype = board_data[j].platform_subtype;
367 dt_entry_array[k].pmic_rev[0]= pmic_data[n].pmic_version[0];
368 dt_entry_array[k].pmic_rev[1]= pmic_data[n].pmic_version[1];
369 dt_entry_array[k].pmic_rev[2]= pmic_data[n].pmic_version[2];
370 dt_entry_array[k].pmic_rev[3]= pmic_data[n].pmic_version[3];
371 dt_entry_array[k].offset = (uint32_t)dtb;
372 dt_entry_array[k].size = dtb_size;
373 k++;
374 }
375
376 } else {
377 dt_entry_array[k].platform_id = platform_data[i].platform_id;
378 dt_entry_array[k].soc_rev = platform_data[i].soc_rev;
379 dt_entry_array[k].variant_id = board_data[j].variant_id;
380 dt_entry_array[k].board_hw_subtype = board_data[j].platform_subtype;
381 dt_entry_array[k].pmic_rev[0]= board_pmic_target(0);
382 dt_entry_array[k].pmic_rev[1]= board_pmic_target(1);
383 dt_entry_array[k].pmic_rev[2]= board_pmic_target(2);
384 dt_entry_array[k].pmic_rev[3]= board_pmic_target(3);
385 dt_entry_array[k].offset = (uint32_t)dtb;
386 dt_entry_array[k].size = dtb_size;
vijay kumar89d36d82014-06-30 19:32:18 +0530387 k++;
388 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700389 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800390 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700391
Lijuan Gao9f152862014-08-18 13:45:24 +0800392 for (i=0 ;i < num_entries; i++) {
393 dprintf(SPEW, "Found an appended flattened device tree (%s - %u %u %u 0x%x)\n",
394 *model ? model : "unknown",
395 dt_entry_array[i].platform_id, dt_entry_array[i].variant_id, dt_entry_array[i].board_hw_subtype, dt_entry_array[i].soc_rev);
vijay kumar89d36d82014-06-30 19:32:18 +0530396
Lijuan Gao9f152862014-08-18 13:45:24 +0800397 if (platform_dt_absolute_match(&(dt_entry_array[i]), dtb_list)) {
398 dprintf(SPEW, "Device tree exact match the board: <%u %u %u 0x%x> == <%u %u %u 0x%x>\n",
399 dt_entry_array[i].platform_id,
400 dt_entry_array[i].variant_id,
401 dt_entry_array[i].soc_rev,
402 dt_entry_array[i].board_hw_subtype,
403 board_platform_id(),
404 board_hardware_id(),
405 board_hardware_subtype(),
406 board_soc_version());
vijay kumar89d36d82014-06-30 19:32:18 +0530407
Lijuan Gao9f152862014-08-18 13:45:24 +0800408 } else {
409 dprintf(SPEW, "Device tree's msm_id doesn't match the board: <%u %u %u 0x%x> != <%u %u %u 0x%x>\n",
410 dt_entry_array[i].platform_id,
411 dt_entry_array[i].variant_id,
412 dt_entry_array[i].soc_rev,
413 dt_entry_array[i].board_hw_subtype,
414 board_platform_id(),
415 board_hardware_id(),
416 board_hardware_subtype(),
417 board_soc_version());
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700418 }
419 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800420
421 free(board_data);
422 free(platform_data);
423 if (pmic_data)
424 free(pmic_data);
425 free(dt_entry_array);
Dima Zavinc46f8382013-05-03 12:23:06 -0700426 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800427 if (model)
vijay kumar89d36d82014-06-30 19:32:18 +0530428 free(model);
Lijuan Gao9f152862014-08-18 13:45:24 +0800429 return true;
Dima Zavinc46f8382013-05-03 12:23:06 -0700430}
431
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800432/*
Dima Zavin77e41f32013-03-06 16:10:43 -0800433 * Will relocate the DTB to the tags addr if the device tree is found and return
434 * its address
435 *
436 * Arguments: kernel - Start address of the kernel loaded in RAM
437 * tags - Start address of the tags loaded in RAM
Channagoud Kadabi704cd562013-04-25 15:19:59 -0700438 * kernel_size - Size of the kernel in bytes
439 *
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800440 * Return Value: DTB address : If appended device tree is found
Dima Zavin77e41f32013-03-06 16:10:43 -0800441 * 'NULL' : Otherwise
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800442 */
Matthew Qinbb7923d2015-02-09 10:56:09 +0800443void *dev_tree_appended(void *kernel, uint32_t kernel_size, uint32_t dtb_offset, void *tags)
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800444{
Parth Dixit97e47bb2016-03-07 17:20:44 +0530445 uintptr_t kernel_end = (uintptr_t)kernel + kernel_size;
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800446 uint32_t app_dtb_offset = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800447 void *dtb = NULL;
Shashank Mittalc0f10282013-07-15 14:53:31 -0700448 void *bestmatch_tag = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800449 struct dt_entry *best_match_dt_entry = NULL;
Shashank Mittalc0f10282013-07-15 14:53:31 -0700450 uint32_t bestmatch_tag_size;
Lijuan Gao9f152862014-08-18 13:45:24 +0800451 struct dt_entry_node *dt_entry_queue = NULL;
452 struct dt_entry_node *dt_node_tmp1 = NULL;
453 struct dt_entry_node *dt_node_tmp2 = NULL;
454
Lijuan Gao9f152862014-08-18 13:45:24 +0800455 /* Initialize the dtb entry node*/
456 dt_entry_queue = (struct dt_entry_node *)
457 malloc(sizeof(struct dt_entry_node));
458
459 if (!dt_entry_queue) {
460 dprintf(CRITICAL, "Out of memory\n");
461 return NULL;
462 }
463 list_initialize(&dt_entry_queue->node);
464
Matthew Qinbb7923d2015-02-09 10:56:09 +0800465 if (dtb_offset)
466 app_dtb_offset = dtb_offset;
467 else
468 memcpy((void*) &app_dtb_offset, (void*) (kernel + DTB_OFFSET), sizeof(uint32_t));
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800469
vijay kumare2a5ea82014-06-25 12:24:14 +0530470 if (((uintptr_t)kernel + (uintptr_t)app_dtb_offset) < (uintptr_t)kernel) {
471 return NULL;
472 }
Parth Dixit97e47bb2016-03-07 17:20:44 +0530473 dtb = (void *)((uintptr_t)kernel + app_dtb_offset);
474
vijay kumare2a5ea82014-06-25 12:24:14 +0530475 while (((uintptr_t)dtb + sizeof(struct fdt_header)) < (uintptr_t)kernel_end) {
Dima Zavinc46f8382013-05-03 12:23:06 -0700476 struct fdt_header dtb_hdr;
477 uint32_t dtb_size;
Dima Zavin77e41f32013-03-06 16:10:43 -0800478
Dima Zavinc46f8382013-05-03 12:23:06 -0700479 /* the DTB could be unaligned, so extract the header,
480 * and operate on it separately */
481 memcpy(&dtb_hdr, dtb, sizeof(struct fdt_header));
482 if (fdt_check_header((const void *)&dtb_hdr) != 0 ||
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +0530483 fdt_check_header_ext((const void *)&dtb_hdr) != 0 ||
vijay kumare2a5ea82014-06-25 12:24:14 +0530484 ((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) < (uintptr_t)dtb) ||
485 ((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) > (uintptr_t)kernel_end))
Dima Zavinc46f8382013-05-03 12:23:06 -0700486 break;
487 dtb_size = fdt_totalsize(&dtb_hdr);
488
vijay kumar4f4405f2014-08-08 11:49:53 +0530489 if (check_aboot_addr_range_overlap((uint32_t)tags, dtb_size)) {
vijay kumarb05eed22014-06-24 16:30:18 +0530490 dprintf(CRITICAL, "Tags addresses overlap with aboot addresses.\n");
491 return NULL;
492 }
493
Lijuan Gao9f152862014-08-18 13:45:24 +0800494 dev_tree_compatible(dtb, dtb_size, dt_entry_queue);
Dima Zavinc46f8382013-05-03 12:23:06 -0700495
496 /* goto the next device tree if any */
497 dtb += dtb_size;
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800498 }
Dima Zavinc46f8382013-05-03 12:23:06 -0700499
Lijuan Gao9f152862014-08-18 13:45:24 +0800500 best_match_dt_entry = platform_dt_match_best(dt_entry_queue);
501 if (best_match_dt_entry){
502 bestmatch_tag = (void *)best_match_dt_entry->offset;
503 bestmatch_tag_size = best_match_dt_entry->size;
504 dprintf(INFO, "Best match DTB tags %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
505 best_match_dt_entry->platform_id, best_match_dt_entry->variant_id,
506 best_match_dt_entry->board_hw_subtype, best_match_dt_entry->soc_rev,
507 best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],
508 best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],
509 best_match_dt_entry->offset, best_match_dt_entry->size);
510 dprintf(INFO, "Using pmic info 0x%0x/0x%x/0x%x/0x%0x for device 0x%0x/0x%x/0x%x/0x%0x\n",
511 best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],
512 best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],
513 board_pmic_target(0), board_pmic_target(1),
514 board_pmic_target(2), board_pmic_target(3));
515 }
516 /* free queue's memory */
517 list_for_every_entry(&dt_entry_queue->node, dt_node_tmp1, dt_node, node) {
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -0800518 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +0800519 dt_entry_list_delete(dt_node_tmp1);
520 dt_node_tmp1 = dt_node_tmp2;
521 }
522
Shashank Mittalc0f10282013-07-15 14:53:31 -0700523 if(bestmatch_tag) {
Shashank Mittalc0f10282013-07-15 14:53:31 -0700524 memcpy(tags, bestmatch_tag, bestmatch_tag_size);
525 /* clear out the old DTB magic so kernel doesn't find it */
526 *((uint32_t *)(kernel + app_dtb_offset)) = 0;
527 return tags;
528 }
529
Dima Zavinc46f8382013-05-03 12:23:06 -0700530 dprintf(CRITICAL, "DTB offset is incorrect, kernel image does not have appended DTB\n");
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800531
David Ng59c4a782015-05-14 15:51:44 -0700532 dprintf(INFO, "Device info 0x%08x/%08x/0x%08x/%u, pmic 0x%0x/0x%x/0x%x/0x%0x\n",
533 board_platform_id(), board_soc_version(),
534 board_target_id(), board_hardware_subtype(),
535 board_pmic_target(0), board_pmic_target(1),
536 board_pmic_target(2), board_pmic_target(3));
Dima Zavin77e41f32013-03-06 16:10:43 -0800537 return NULL;
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800538}
539
Joel Kingaa335dc2013-06-03 16:11:08 -0700540/* Returns 0 if the device tree is valid. */
Deepa Dinamani87252952013-09-09 13:58:27 -0700541int dev_tree_validate(struct dt_table *table, unsigned int page_size, uint32_t *dt_hdr_size)
Joel Kingaa335dc2013-06-03 16:11:08 -0700542{
543 int dt_entry_size;
Channagoud Kadabid87c2772014-06-20 15:41:55 -0700544 uint64_t hdr_size;
Joel Kingaa335dc2013-06-03 16:11:08 -0700545
546 /* Validate the device tree table header */
547 if(table->magic != DEV_TREE_MAGIC) {
548 dprintf(CRITICAL, "ERROR: Bad magic in device tree table \n");
549 return -1;
550 }
551
552 if (table->version == DEV_TREE_VERSION_V1) {
553 dt_entry_size = sizeof(struct dt_entry_v1);
554 } else if (table->version == DEV_TREE_VERSION_V2) {
Lijuan Gao9f152862014-08-18 13:45:24 +0800555 dt_entry_size = sizeof(struct dt_entry_v2);
556 } else if (table->version == DEV_TREE_VERSION_V3) {
Joel Kingaa335dc2013-06-03 16:11:08 -0700557 dt_entry_size = sizeof(struct dt_entry);
558 } else {
559 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
560 table->version);
561 return -1;
562 }
563
Channagoud Kadabid87c2772014-06-20 15:41:55 -0700564 hdr_size = (uint64_t)table->num_entries * dt_entry_size + DEV_TREE_HEADER_SIZE;
565
Deepa Dinamani87252952013-09-09 13:58:27 -0700566 /* Roundup to page_size. */
567 hdr_size = ROUNDUP(hdr_size, page_size);
568
Channagoud Kadabid87c2772014-06-20 15:41:55 -0700569 if (hdr_size > UINT_MAX)
570 return -1;
571 else
572 *dt_hdr_size = hdr_size & UINT_MAX;
Joel Kingaa335dc2013-06-03 16:11:08 -0700573
574 return 0;
575}
576
Lijuan Gao9f152862014-08-18 13:45:24 +0800577static int platform_dt_absolute_match(struct dt_entry *cur_dt_entry, struct dt_entry_node *dt_list)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700578{
Lijuan Gaof8e95722014-12-23 03:03:12 -0500579 uint32_t cur_dt_hlos_ddr;
Lijuan Gao9f152862014-08-18 13:45:24 +0800580 uint32_t cur_dt_hw_platform;
581 uint32_t cur_dt_hw_subtype;
582 uint32_t cur_dt_msm_id;
583 dt_node *dt_node_tmp = NULL;
Channagoud Kadabi571193a2014-02-05 13:58:49 -0800584
Lijuan Gao9f152862014-08-18 13:45:24 +0800585 /* Platform-id
586 * bit no |31 24|23 16|15 0|
587 * |reserved|foundry-id|msm-id|
588 */
589 cur_dt_msm_id = (cur_dt_entry->platform_id & 0x0000ffff);
590 cur_dt_hw_platform = (cur_dt_entry->variant_id & 0x000000ff);
Lijuan Gao0621b862014-09-02 10:02:52 +0800591 cur_dt_hw_subtype = (cur_dt_entry->board_hw_subtype & 0xff);
Lijuan Gao9f152862014-08-18 13:45:24 +0800592
Lijuan Gaof8e95722014-12-23 03:03:12 -0500593 /* Determine the bits 10:8 to check the DT with the DDR Size */
594 cur_dt_hlos_ddr = (cur_dt_entry->board_hw_subtype & 0x700);
Channagoud Kadabi571193a2014-02-05 13:58:49 -0800595
Lijuan Gao9f152862014-08-18 13:45:24 +0800596 /* 1. must match the msm_id, platform_hw_id, platform_subtype and DDR size
597 * soc, board major/minor, pmic major/minor must less than board info
598 * 2. find the matched DTB then return 1
599 * 3. otherwise return 0
Maria Yu2e2d2c22013-07-03 19:20:33 +0800600 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800601 if((cur_dt_msm_id == (board_platform_id() & 0x0000ffff)) &&
602 (cur_dt_hw_platform == board_hardware_id()) &&
603 (cur_dt_hw_subtype == board_hardware_subtype()) &&
Lijuan Gaof8e95722014-12-23 03:03:12 -0500604 (cur_dt_hlos_ddr == (target_get_hlos_subtype() & 0x700)) &&
Lijuan Gao9f152862014-08-18 13:45:24 +0800605 (cur_dt_entry->soc_rev <= board_soc_version()) &&
606 ((cur_dt_entry->variant_id & 0x00ffff00) <= (board_target_id() & 0x00ffff00)) &&
607 ((cur_dt_entry->pmic_rev[0] & 0x00ffff00) <= (board_pmic_target(0) & 0x00ffff00)) &&
608 ((cur_dt_entry->pmic_rev[1] & 0x00ffff00) <= (board_pmic_target(1) & 0x00ffff00)) &&
609 ((cur_dt_entry->pmic_rev[2] & 0x00ffff00) <= (board_pmic_target(2) & 0x00ffff00)) &&
610 ((cur_dt_entry->pmic_rev[3] & 0x00ffff00) <= (board_pmic_target(3) & 0x00ffff00))) {
Maria Yu2e2d2c22013-07-03 19:20:33 +0800611
Lijuan Gao9f152862014-08-18 13:45:24 +0800612 dt_node_tmp = dt_entry_list_init();
613 memcpy((char*)dt_node_tmp->dt_entry_m,(char*)cur_dt_entry, sizeof(struct dt_entry));
614
615 dprintf(SPEW, "Add DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
616 dt_node_tmp->dt_entry_m->platform_id, dt_node_tmp->dt_entry_m->variant_id,
617 dt_node_tmp->dt_entry_m->board_hw_subtype, dt_node_tmp->dt_entry_m->soc_rev,
618 dt_node_tmp->dt_entry_m->pmic_rev[0], dt_node_tmp->dt_entry_m->pmic_rev[1],
619 dt_node_tmp->dt_entry_m->pmic_rev[2], dt_node_tmp->dt_entry_m->pmic_rev[3],
620 dt_node_tmp->dt_entry_m->offset, dt_node_tmp->dt_entry_m->size);
621
622 insert_dt_entry_in_queue(dt_list, dt_node_tmp);
623 return 1;
624 }
625 return 0;
626}
627
628static int platform_dt_absolute_compat_match(struct dt_entry_node *dt_list, uint32_t dtb_info) {
629 struct dt_entry_node *dt_node_tmp1 = NULL;
630 struct dt_entry_node *dt_node_tmp2 = NULL;
631 uint32_t current_info = 0;
632 uint32_t board_info = 0;
633 uint32_t best_info = 0;
634 uint32_t current_pmic_model[4] = {0, 0, 0, 0};
635 uint32_t board_pmic_model[4] = {0, 0, 0, 0};
636 uint32_t best_pmic_model[4] = {0, 0, 0, 0};
637 uint32_t delete_current_dt = 0;
638 uint32_t i;
639
640 /* start to select the exact entry
641 * default to exact match 0, if find current DTB entry info is the same as board info,
642 * then exact match board info.
643 */
644 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
645 if (!dt_node_tmp1){
646 dprintf(SPEW, "Current node is the end\n");
647 break;
648 }
649 switch(dtb_info) {
650 case DTB_FOUNDRY:
651 current_info = ((dt_node_tmp1->dt_entry_m->platform_id) & 0x00ff0000);
Channagoud Kadabi4cffc272014-10-29 11:23:26 -0700652 board_info = board_foundry_id() << 16;
Lijuan Gao9f152862014-08-18 13:45:24 +0800653 break;
654 case DTB_PMIC_MODEL:
655 for (i = 0; i < 4; i++) {
656 current_pmic_model[i] = (dt_node_tmp1->dt_entry_m->pmic_rev[i] & 0xff);
657 board_pmic_model[i] = (board_pmic_target(i) & 0xff);
658 }
659 break;
Lijuan Gaof8e95722014-12-23 03:03:12 -0500660 case DTB_PANEL_TYPE:
661 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0x1800);
662 board_info = (target_get_hlos_subtype() & 0x1800);
663 break;
664 case DTB_BOOT_DEVICE:
665 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0xf0000);
666 board_info = (target_get_hlos_subtype() & 0xf0000);
667 break;
Lijuan Gao9f152862014-08-18 13:45:24 +0800668 default:
669 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
670 dtb_info);
Maria Yuca51ee22013-06-27 21:45:24 +0800671 return 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800672 }
673
674 if (dtb_info == DTB_PMIC_MODEL) {
675 if ((current_pmic_model[0] == board_pmic_model[0]) &&
676 (current_pmic_model[1] == board_pmic_model[1]) &&
677 (current_pmic_model[2] == board_pmic_model[2]) &&
678 (current_pmic_model[3] == board_pmic_model[3])) {
679
680 for (i = 0; i < 4; i++) {
681 best_pmic_model[i] = current_pmic_model[i];
682 }
683 break;
684 }
685 } else {
686 if (current_info == board_info) {
687 best_info = current_info;
688 break;
689 }
690 }
691 }
692
693 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
694 if (!dt_node_tmp1){
695 dprintf(SPEW, "Current node is the end\n");
696 break;
697 }
698 switch(dtb_info) {
699 case DTB_FOUNDRY:
700 current_info = ((dt_node_tmp1->dt_entry_m->platform_id) & 0x00ff0000);
701 break;
702 case DTB_PMIC_MODEL:
703 for (i = 0; i < 4; i++) {
704 current_pmic_model[i] = (dt_node_tmp1->dt_entry_m->pmic_rev[i] & 0xff);
705 }
706 break;
Lijuan Gaof8e95722014-12-23 03:03:12 -0500707 case DTB_PANEL_TYPE:
708 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0x1800);
709 break;
710 case DTB_BOOT_DEVICE:
711 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0xf0000);
712 break;
Lijuan Gao9f152862014-08-18 13:45:24 +0800713 default:
714 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
715 dtb_info);
716 return 0;
717 }
718
719 if (dtb_info == DTB_PMIC_MODEL) {
720 if ((current_pmic_model[0] != best_pmic_model[0]) ||
721 (current_pmic_model[1] != best_pmic_model[1]) ||
722 (current_pmic_model[2] != best_pmic_model[2]) ||
723 (current_pmic_model[3] != best_pmic_model[3])) {
724
725 delete_current_dt = 1;
726 }
727 } else {
728 if (current_info != best_info) {
729 delete_current_dt = 1;
730 }
731 }
732
733 if (delete_current_dt) {
734 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
735 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
736 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
737 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
738 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
739 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
740
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -0800741 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +0800742 dt_entry_list_delete(dt_node_tmp1);
743 dt_node_tmp1 = dt_node_tmp2;
744 delete_current_dt = 0;
Maria Yuca51ee22013-06-27 21:45:24 +0800745 }
746 }
Maria Yuca51ee22013-06-27 21:45:24 +0800747
Maria Yu2e2d2c22013-07-03 19:20:33 +0800748 return 1;
Maria Yuca51ee22013-06-27 21:45:24 +0800749}
750
Lijuan Gao9f152862014-08-18 13:45:24 +0800751static int update_dtb_entry_node(struct dt_entry_node *dt_list, uint32_t dtb_info) {
752 struct dt_entry_node *dt_node_tmp1 = NULL;
753 struct dt_entry_node *dt_node_tmp2 = NULL;
754 uint32_t current_info = 0;
755 uint32_t board_info = 0;
756 uint32_t best_info = 0;
757
758 /* start to select the best entry*/
759 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
760 if (!dt_node_tmp1){
761 dprintf(SPEW, "Current node is the end\n");
762 break;
763 }
764 switch(dtb_info) {
765 case DTB_SOC:
766 current_info = dt_node_tmp1->dt_entry_m->soc_rev;
767 board_info = board_soc_version();
768 break;
769 case DTB_MAJOR_MINOR:
770 current_info = ((dt_node_tmp1->dt_entry_m->variant_id) & 0x00ffff00);
771 board_info = (board_target_id() & 0x00ffff00);
772 break;
773 case DTB_PMIC0:
774 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[0]) & 0x00ffff00);
775 board_info = (board_pmic_target(0) & 0x00ffff00);
776 break;
777 case DTB_PMIC1:
778 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[1]) & 0x00ffff00);
779 board_info = (board_pmic_target(1) & 0x00ffff00);
780 break;
781 case DTB_PMIC2:
782 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[2]) & 0x00ffff00);
783 board_info = (board_pmic_target(2) & 0x00ffff00);
784 break;
785 case DTB_PMIC3:
786 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[3]) & 0x00ffff00);
787 board_info = (board_pmic_target(3) & 0x00ffff00);
788 break;
789 default:
790 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
791 dtb_info);
792 return 0;
793 }
794
795 if (current_info == board_info) {
796 best_info = current_info;
797 break;
798 }
799 if ((current_info < board_info) && (current_info > best_info)) {
800 best_info = current_info;
801 }
802 if (current_info < best_info) {
803 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
804 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
805 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
806 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
807 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
808 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
809
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -0800810 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +0800811 dt_entry_list_delete(dt_node_tmp1);
812 dt_node_tmp1 = dt_node_tmp2;
813 }
814 }
815
816 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
817 if (!dt_node_tmp1){
818 dprintf(SPEW, "Current node is the end\n");
819 break;
820 }
821 switch(dtb_info) {
822 case DTB_SOC:
823 current_info = dt_node_tmp1->dt_entry_m->soc_rev;
824 break;
825 case DTB_MAJOR_MINOR:
826 current_info = ((dt_node_tmp1->dt_entry_m->variant_id) & 0x00ffff00);
827 break;
828 case DTB_PMIC0:
829 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[0]) & 0x00ffff00);
830 break;
831 case DTB_PMIC1:
832 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[1]) & 0x00ffff00);
833 break;
834 case DTB_PMIC2:
835 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[2]) & 0x00ffff00);
836 break;
837 case DTB_PMIC3:
838 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[3]) & 0x00ffff00);
839 break;
840 default:
841 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
842 dtb_info);
843 return 0;
844 }
845
846 if (current_info != best_info) {
847 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
848 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
849 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
850 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
851 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
852 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
853
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -0800854 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +0800855 dt_entry_list_delete(dt_node_tmp1);
856 dt_node_tmp1 = dt_node_tmp2;
857 }
858 }
859 return 1;
860}
861
862static struct dt_entry *platform_dt_match_best(struct dt_entry_node *dt_list)
863{
864 struct dt_entry_node *dt_node_tmp1 = NULL;
865
866 /* check Foundry id
867 * the foundry id must exact match board founddry id, this is compatibility check,
868 * if couldn't find the exact match from DTB, will exact match 0x0.
869 */
870 if (!platform_dt_absolute_compat_match(dt_list, DTB_FOUNDRY))
871 return NULL;
872
873 /* check PMIC model
874 * the PMIC model must exact match board PMIC model, this is compatibility check,
875 * if couldn't find the exact match from DTB, will exact match 0x0.
876 */
877 if (!platform_dt_absolute_compat_match(dt_list, DTB_PMIC_MODEL))
878 return NULL;
879
Lijuan Gaof8e95722014-12-23 03:03:12 -0500880 /* check panel type
881 * the panel type must exact match board panel type, this is compatibility check,
882 * if couldn't find the exact match from DTB, will exact match 0x0.
883 */
884 if (!platform_dt_absolute_compat_match(dt_list, DTB_PANEL_TYPE))
885 return NULL;
886
887 /* check boot device subtype
888 * the boot device subtype must exact match board boot device subtype, this is compatibility check,
889 * if couldn't find the exact match from DTB, will exact match 0x0.
890 */
891 if (!platform_dt_absolute_compat_match(dt_list, DTB_BOOT_DEVICE))
892 return NULL;
893
Lijuan Gao9f152862014-08-18 13:45:24 +0800894 /* check soc version
895 * the suitable soc version must less than or equal to board soc version
896 */
897 if (!update_dtb_entry_node(dt_list, DTB_SOC))
898 return NULL;
899
900 /*check major and minor version
901 * the suitable major&minor version must less than or equal to board major&minor version
902 */
903 if (!update_dtb_entry_node(dt_list, DTB_MAJOR_MINOR))
904 return NULL;
905
906 /*check pmic info
907 * the suitable pmic major&minor info must less than or equal to board pmic major&minor version
908 */
909 if (!update_dtb_entry_node(dt_list, DTB_PMIC0))
910 return NULL;
911 if (!update_dtb_entry_node(dt_list, DTB_PMIC1))
912 return NULL;
913 if (!update_dtb_entry_node(dt_list, DTB_PMIC2))
914 return NULL;
915 if (!update_dtb_entry_node(dt_list, DTB_PMIC3))
916 return NULL;
917
918 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
919 if (!dt_node_tmp1) {
920 dprintf(CRITICAL, "ERROR: Couldn't find the suitable DTB!\n");
921 return NULL;
922 }
923 if (dt_node_tmp1->dt_entry_m)
924 return dt_node_tmp1->dt_entry_m;
925 }
926
927 return NULL;
928}
929
930/* Function to obtain the index information for the correct device tree
931 * based on the platform data.
932 * If a matching device tree is found, the information is returned in the
933 * "dt_entry_info" out parameter and a function value of 0 is returned, otherwise
934 * a non-zero function value is returned.
935 */
936int dev_tree_get_entry_info(struct dt_table *table, struct dt_entry *dt_entry_info)
Maria Yuca51ee22013-06-27 21:45:24 +0800937{
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700938 uint32_t i;
Lijuan Gao9f152862014-08-18 13:45:24 +0800939 unsigned char *table_ptr = NULL;
Joel Kingaa335dc2013-06-03 16:11:08 -0700940 struct dt_entry dt_entry_buf_1;
Lijuan Gao9f152862014-08-18 13:45:24 +0800941 struct dt_entry *cur_dt_entry = NULL;
942 struct dt_entry *best_match_dt_entry = NULL;
943 struct dt_entry_v1 *dt_entry_v1 = NULL;
944 struct dt_entry_v2 *dt_entry_v2 = NULL;
945 struct dt_entry_node *dt_entry_queue = NULL;
946 struct dt_entry_node *dt_node_tmp1 = NULL;
947 struct dt_entry_node *dt_node_tmp2 = NULL;
Maria Yu2e2d2c22013-07-03 19:20:33 +0800948 uint32_t found = 0;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700949
Joel Kingaa335dc2013-06-03 16:11:08 -0700950 if (!dt_entry_info) {
951 dprintf(CRITICAL, "ERROR: Bad parameter passed to %s \n",
952 __func__);
953 return -1;
954 }
955
956 table_ptr = (unsigned char *)table + DEV_TREE_HEADER_SIZE;
957 cur_dt_entry = &dt_entry_buf_1;
958 best_match_dt_entry = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800959 dt_entry_queue = (struct dt_entry_node *)
960 malloc(sizeof(struct dt_entry_node));
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700961
Lijuan Gao9f152862014-08-18 13:45:24 +0800962 if (!dt_entry_queue) {
963 dprintf(CRITICAL, "Out of memory\n");
964 return -1;
965 }
966
967 list_initialize(&dt_entry_queue->node);
968 dprintf(INFO, "DTB Total entry: %d, DTB version: %d\n", table->num_entries, table->version);
Maria Yu2e2d2c22013-07-03 19:20:33 +0800969 for(i = 0; found == 0 && i < table->num_entries; i++)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700970 {
Joel Kingaa335dc2013-06-03 16:11:08 -0700971 memset(cur_dt_entry, 0, sizeof(struct dt_entry));
972 switch(table->version) {
973 case DEV_TREE_VERSION_V1:
974 dt_entry_v1 = (struct dt_entry_v1 *)table_ptr;
975 cur_dt_entry->platform_id = dt_entry_v1->platform_id;
976 cur_dt_entry->variant_id = dt_entry_v1->variant_id;
977 cur_dt_entry->soc_rev = dt_entry_v1->soc_rev;
Lijuan Gao9f152862014-08-18 13:45:24 +0800978 cur_dt_entry->board_hw_subtype = (dt_entry_v1->variant_id >> 0x18);
979 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
980 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
981 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
982 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
Joel Kingaa335dc2013-06-03 16:11:08 -0700983 cur_dt_entry->offset = dt_entry_v1->offset;
984 cur_dt_entry->size = dt_entry_v1->size;
985 table_ptr += sizeof(struct dt_entry_v1);
986 break;
987 case DEV_TREE_VERSION_V2:
Lijuan Gao9f152862014-08-18 13:45:24 +0800988 dt_entry_v2 = (struct dt_entry_v2*)table_ptr;
989 cur_dt_entry->platform_id = dt_entry_v2->platform_id;
990 cur_dt_entry->variant_id = dt_entry_v2->variant_id;
991 cur_dt_entry->soc_rev = dt_entry_v2->soc_rev;
992 /* For V2 version of DTBs we have platform version field as part
993 * of variant ID, in such case the subtype will be mentioned as 0x0
994 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
995 * SS -- Subtype
996 * PM -- Platform major version
997 * Pm -- Platform minor version
998 * PH -- Platform hardware CDP/MTP
999 * In such case to make it compatible with LK algorithm move the subtype
1000 * from variant_id to subtype field
1001 */
1002 if (dt_entry_v2->board_hw_subtype == 0)
1003 cur_dt_entry->board_hw_subtype = (cur_dt_entry->variant_id >> 0x18);
1004 else
1005 cur_dt_entry->board_hw_subtype = dt_entry_v2->board_hw_subtype;
1006 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
1007 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
1008 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
1009 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
1010 cur_dt_entry->offset = dt_entry_v2->offset;
1011 cur_dt_entry->size = dt_entry_v2->size;
1012 table_ptr += sizeof(struct dt_entry_v2);
1013 break;
1014 case DEV_TREE_VERSION_V3:
Joel Kingaa335dc2013-06-03 16:11:08 -07001015 memcpy(cur_dt_entry, (struct dt_entry *)table_ptr,
1016 sizeof(struct dt_entry));
Lijuan Gao9f152862014-08-18 13:45:24 +08001017 /* For V3 version of DTBs we have platform version field as part
1018 * of variant ID, in such case the subtype will be mentioned as 0x0
1019 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
1020 * SS -- Subtype
1021 * PM -- Platform major version
1022 * Pm -- Platform minor version
1023 * PH -- Platform hardware CDP/MTP
1024 * In such case to make it compatible with LK algorithm move the subtype
1025 * from variant_id to subtype field
1026 */
1027 if (cur_dt_entry->board_hw_subtype == 0)
1028 cur_dt_entry->board_hw_subtype = (cur_dt_entry->variant_id >> 0x18);
1029
Joel Kingaa335dc2013-06-03 16:11:08 -07001030 table_ptr += sizeof(struct dt_entry);
1031 break;
1032 default:
1033 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
1034 table->version);
Lijuan Gao9f152862014-08-18 13:45:24 +08001035 free(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001036 return -1;
1037 }
1038
Lijuan Gao9f152862014-08-18 13:45:24 +08001039 /* DTBs must match the platform_id, platform_hw_id, platform_subtype and DDR size.
1040 * The satisfactory DTBs are stored in dt_entry_queue
1041 */
1042 platform_dt_absolute_match(cur_dt_entry, dt_entry_queue);
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -08001043
Lijuan Gao9f152862014-08-18 13:45:24 +08001044 }
1045 best_match_dt_entry = platform_dt_match_best(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001046 if (best_match_dt_entry) {
1047 *dt_entry_info = *best_match_dt_entry;
Maria Yu2e2d2c22013-07-03 19:20:33 +08001048 found = 1;
1049 }
1050
1051 if (found != 0) {
Sundarajan Srinivasan763c0db2014-05-20 17:08:36 -07001052 dprintf(INFO, "Using DTB entry 0x%08x/%08x/0x%08x/%u for device 0x%08x/%08x/0x%08x/%u\n",
David Ng618293a2013-06-25 12:29:03 -07001053 dt_entry_info->platform_id, dt_entry_info->soc_rev,
1054 dt_entry_info->variant_id, dt_entry_info->board_hw_subtype,
Lijuan Gao9f152862014-08-18 13:45:24 +08001055 board_platform_id(), board_soc_version(),
1056 board_target_id(), board_hardware_subtype());
1057 if (dt_entry_info->pmic_rev[0] == 0 && dt_entry_info->pmic_rev[0] == 0 &&
1058 dt_entry_info->pmic_rev[0] == 0 && dt_entry_info->pmic_rev[0] == 0) {
1059 dprintf(SPEW, "No maintain pmic info in DTB, device pmic info is 0x%0x/0x%x/0x%x/0x%0x\n",
1060 board_pmic_target(0), board_pmic_target(1),
1061 board_pmic_target(2), board_pmic_target(3));
1062 } else {
1063 dprintf(INFO, "Using pmic info 0x%0x/0x%x/0x%x/0x%0x for device 0x%0x/0x%x/0x%x/0x%0x\n",
1064 dt_entry_info->pmic_rev[0], dt_entry_info->pmic_rev[1],
1065 dt_entry_info->pmic_rev[2], dt_entry_info->pmic_rev[3],
1066 board_pmic_target(0), board_pmic_target(1),
1067 board_pmic_target(2), board_pmic_target(3));
1068 }
Joel Kingaa335dc2013-06-03 16:11:08 -07001069 return 0;
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -08001070 }
1071
Lijuan Gao9f152862014-08-18 13:45:24 +08001072 dprintf(CRITICAL, "ERROR: Unable to find suitable device tree for device (%u/0x%08x/0x%08x/%u)\n",
1073 board_platform_id(), board_soc_version(),
1074 board_target_id(), board_hardware_subtype());
1075
1076 list_for_every_entry(&dt_entry_queue->node, dt_node_tmp1, dt_node, node) {
1077 /* free node memory */
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001078 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001079 dt_entry_list_delete(dt_node_tmp1);
1080 dt_node_tmp1 = dt_node_tmp2;
1081 }
1082 free(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001083 return -1;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001084}
1085
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001086/* Function to add the first RAM partition info to the device tree.
1087 * Note: The function replaces the reg property in the "/memory" node
1088 * with the addr and size provided.
1089 */
1090int dev_tree_add_first_mem_info(uint32_t *fdt, uint32_t offset, uint32_t addr, uint32_t size)
1091{
1092 int ret;
1093
1094 ret = fdt_setprop_u32(fdt, offset, "reg", addr);
1095
1096 if (ret)
1097 {
1098 dprintf(CRITICAL, "Failed to add the memory information addr: %d\n",
1099 ret);
1100 }
1101
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001102 ret = fdt_appendprop_u32(fdt, offset, "reg", size);
1103
1104 if (ret)
1105 {
1106 dprintf(CRITICAL, "Failed to add the memory information size: %d\n",
1107 ret);
1108 }
1109
1110 return ret;
1111}
1112
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001113static int dev_tree_query_memory_cell_sizes(void *fdt, struct dt_mem_node_info *mem_node, uint32_t mem_node_offset)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001114{
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001115 int len;
1116 uint32_t *valp;
1117 int ret;
1118 uint32_t offset;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001119
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001120 mem_node->offset = mem_node_offset;
1121
1122 /* Get offset of the root node */
1123 ret = fdt_path_offset(fdt, "/");
1124 if (ret < 0)
1125 {
1126 dprintf(CRITICAL, "Could not find memory node.\n");
1127 return ret;
1128 }
1129
1130 offset = ret;
1131
1132 /* Find the #address-cells size. */
1133 valp = (uint32_t*)fdt_getprop(fdt, offset, "#address-cells", &len);
Lijuan Gaoae0927b2014-07-18 17:16:16 +08001134 if (len <= 0 || !valp)
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001135 {
1136 if (len == -FDT_ERR_NOTFOUND)
1137 {
1138 /* Property not found.
1139 * Assume standard sizes.
1140 */
1141 mem_node->addr_cell_size = 2;
1142 dprintf(CRITICAL, "Using default #addr_cell_size: %u\n", mem_node->addr_cell_size);
1143 }
1144 else
1145 {
1146 dprintf(CRITICAL, "Error finding the #address-cells property\n");
1147 return len;
1148 }
1149 }
1150 else
1151 mem_node->addr_cell_size = fdt32_to_cpu(*valp);
1152
1153 /* Find the #size-cells size. */
1154 valp = (uint32_t*)fdt_getprop(fdt, offset, "#size-cells", &len);
Lijuan Gaoae0927b2014-07-18 17:16:16 +08001155 if (len <= 0 || !valp)
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001156 {
1157 if (len == -FDT_ERR_NOTFOUND)
1158 {
1159 /* Property not found.
1160 * Assume standard sizes.
1161 */
1162 mem_node->size_cell_size = 1;
1163 dprintf(CRITICAL, "Using default #size_cell_size: %u\n", mem_node->size_cell_size);
1164 }
1165 else
1166 {
1167 dprintf(CRITICAL, "Error finding the #size-cells property\n");
1168 return len;
1169 }
1170 }
1171 else
1172 mem_node->size_cell_size = fdt32_to_cpu(*valp);
1173
1174 return 0;
1175}
1176
1177static void dev_tree_update_memory_node(uint32_t offset)
1178{
1179 mem_node.offset = offset;
1180 mem_node.addr_cell_size = 1;
1181 mem_node.size_cell_size = 1;
1182}
1183
1184/* Function to add the subsequent RAM partition info to the device tree. */
1185int dev_tree_add_mem_info(void *fdt, uint32_t offset, uint64_t addr, uint64_t size)
1186{
1187 int ret = 0;
1188
1189 if(smem_get_ram_ptable_version() >= 1)
1190 {
1191 ret = dev_tree_query_memory_cell_sizes(fdt, &mem_node, offset);
1192 if (ret < 0)
1193 {
1194 dprintf(CRITICAL, "Could not find #address-cells and #size-cells properties: ret %d\n", ret);
1195 return ret;
1196 }
1197
1198 }
1199 else
1200 {
1201 dev_tree_update_memory_node(offset);
1202 }
1203
1204 if (!(mem_node.mem_info_cnt))
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001205 {
1206 /* Replace any other reg prop in the memory node. */
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001207
1208 /* cell_size is the number of 32 bit words used to represent an address/length in the device tree.
1209 * memory node in DT can be either 32-bit(cell-size = 1) or 64-bit(cell-size = 2).So when updating
1210 * the memory node in the device tree, we write one word or two words based on cell_size = 1 or 2.
1211 */
1212
1213 if(mem_node.addr_cell_size == 2)
1214 {
1215 ret = fdt_setprop_u32(fdt, mem_node.offset, "reg", addr >> 32);
1216 if(ret)
1217 {
1218 dprintf(CRITICAL, "ERROR: Could not set prop reg for memory node\n");
1219 return ret;
1220 }
1221
1222 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1223 if(ret)
1224 {
1225 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1226 return ret;
1227 }
1228 }
1229 else
1230 {
1231 ret = fdt_setprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1232 if(ret)
1233 {
1234 dprintf(CRITICAL, "ERROR: Could not set prop reg for memory node\n");
1235 return ret;
1236 }
1237 }
1238
1239 mem_node.mem_info_cnt = 1;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001240 }
1241 else
1242 {
1243 /* Append the mem info to the reg prop for subsequent nodes. */
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001244 if(mem_node.addr_cell_size == 2)
1245 {
1246 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", addr >> 32);
1247 if(ret)
1248 {
1249 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1250 return ret;
1251 }
1252 }
1253
1254 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1255 if(ret)
1256 {
1257 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1258 return ret;
1259 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001260 }
1261
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001262 if(mem_node.size_cell_size == 2)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001263 {
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001264 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", size>>32);
1265 if(ret)
1266 {
1267 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1268 return ret;
1269 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001270 }
1271
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001272 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)size);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001273
1274 if (ret)
1275 {
1276 dprintf(CRITICAL, "Failed to add the memory information size: %d\n",
1277 ret);
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001278 return ret;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001279 }
1280
1281 return ret;
1282}
1283
1284/* Top level function that updates the device tree. */
1285int update_device_tree(void *fdt, const char *cmdline,
1286 void *ramdisk, uint32_t ramdisk_size)
1287{
1288 int ret = 0;
1289 uint32_t offset;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001290
1291 /* Check the device tree header */
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +05301292 ret = fdt_check_header(fdt) || fdt_check_header_ext(fdt);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001293 if (ret)
1294 {
1295 dprintf(CRITICAL, "Invalid device tree header \n");
1296 return ret;
1297 }
1298
P.V. Phani Kumar9cd95102016-03-09 12:35:23 +05301299 if (check_aboot_addr_range_overlap((uint32_t)fdt,
1300 (fdt_totalsize(fdt) + DTB_PAD_SIZE))) {
1301 dprintf(CRITICAL, "Error: Fdt addresses overlap with aboot addresses.\n");
1302 return ret;
1303 }
1304
Deepa Dinamani1c970732013-04-19 14:23:01 -07001305 /* Add padding to make space for new nodes and properties. */
1306 ret = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + DTB_PAD_SIZE);
1307 if (ret!= 0)
1308 {
1309 dprintf(CRITICAL, "Failed to move/resize dtb buffer: %d\n", ret);
1310 return ret;
1311 }
1312
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001313 /* Get offset of the memory node */
1314 ret = fdt_path_offset(fdt, "/memory");
1315 if (ret < 0)
1316 {
1317 dprintf(CRITICAL, "Could not find memory node.\n");
1318 return ret;
1319 }
1320
1321 offset = ret;
1322
1323 ret = target_dev_tree_mem(fdt, offset);
1324 if(ret)
1325 {
1326 dprintf(CRITICAL, "ERROR: Cannot update memory node\n");
1327 return ret;
1328 }
1329
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001330 /* Get offset of the chosen node */
1331 ret = fdt_path_offset(fdt, "/chosen");
1332 if (ret < 0)
1333 {
1334 dprintf(CRITICAL, "Could not find chosen node.\n");
1335 return ret;
1336 }
1337
1338 offset = ret;
Maria Yuabde9542014-07-07 14:49:34 +08001339 if (cmdline)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001340 {
Maria Yuabde9542014-07-07 14:49:34 +08001341 /* Adding the cmdline to the chosen node */
1342 ret = fdt_appendprop_string(fdt, offset, (const char*)"bootargs", (const void*)cmdline);
1343 if (ret)
1344 {
1345 dprintf(CRITICAL, "ERROR: Cannot update chosen node [bootargs]\n");
1346 return ret;
1347 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001348 }
1349
Joonwoo Parka5b5f492014-02-13 18:24:48 -08001350 if (ramdisk_size) {
1351 /* Adding the initrd-start to the chosen node */
1352 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-start",
1353 (uint32_t)ramdisk);
1354 if (ret)
1355 {
1356 dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-start]\n");
1357 return ret;
1358 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001359
Joonwoo Parka5b5f492014-02-13 18:24:48 -08001360 /* Adding the initrd-end to the chosen node */
1361 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-end",
1362 ((uint32_t)ramdisk + ramdisk_size));
1363 if (ret)
1364 {
1365 dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-end]\n");
1366 return ret;
1367 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001368 }
1369
1370 fdt_pack(fdt);
1371
Channagoud Kadabiffaea422014-12-05 15:45:41 -08001372#if ENABLE_PARTIAL_GOODS_SUPPORT
1373 update_partial_goods_dtb_nodes(fdt);
1374#endif
1375
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001376 return ret;
1377}