blob: 0337d7ed060707294ff13a0f5dd7f174ea58a4c0 [file] [log] [blame]
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301/* Copyright (c) 2012-2015,2017-2018 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>
Mayank Grover1b6da5d2017-12-19 16:05:46 +053040#include <kernel/event.h>
vijay kumar4f4405f2014-08-08 11:49:53 +053041#include <target.h>
Channagoud Kadabiffaea422014-12-05 15:45:41 -080042#include <partial_goods.h>
Kishor PK536904a2017-07-13 17:18:59 +053043#include <boot_device.h>
44#include <platform.h>
lijuangc76a7632017-12-07 14:37:56 +080045#include <scm.h>
Mayank Grover1b6da5d2017-12-19 16:05:46 +053046#include <partition_parser.h>
47#include <libufdt_sysdeps.h>
48#include <ufdt_overlay.h>
Mayank Grover302432a2017-12-08 17:18:58 +053049#include <boot_stats.h>
Kishor PK536904a2017-07-13 17:18:59 +053050
51#define BOOT_DEV_MAX_LEN 64
52#define NODE_PROPERTY_MAX_LEN 64
Mayank Grover1b6da5d2017-12-19 16:05:46 +053053#define ADD_OF(a, b) (UINT_MAX - b > a) ? (a + b) : UINT_MAX
54#define ADDR_ALIGNMENT 16
55/** 512KB stack **/
56#define DTBO_STACK_SIZE (524288)
57#define MAX_DTBO_SZ 2097152
58
59static bool dtbo_needed = true;
60static void *board_dtb = NULL;
61static void *soc_dtb = NULL;
62static void *soc_dtb_hdr = NULL;
63static void *final_dtb_hdr = NULL;
64static event_t dtbo_event;
65
66typedef enum dtbo_error
67{
68 DTBO_ERROR = 0,
69 DTBO_NOT_SUPPORTED = 1,
70 DTBO_SUCCESS = 2
71}dtbo_error;
72
73dtbo_error ret = DTBO_SUCCESS;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -070074
Joel Kingaa335dc2013-06-03 16:11:08 -070075struct dt_entry_v1
76{
77 uint32_t platform_id;
78 uint32_t variant_id;
79 uint32_t soc_rev;
80 uint32_t offset;
81 uint32_t size;
82};
83
Kishor PK536904a2017-07-13 17:18:59 +053084#if ENABLE_BOOTDEVICE_MOUNT
85/* Look up table for fstab node */
86struct fstab_node
87{
88 const char *parent_node;
89 const char *node_prop;
90 const char *device_path_id;
91};
92
93static struct fstab_node fstab_table =
94{
95 "/firmware/android/fstab", "dev", "/soc/"
96};
97#endif
98
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -070099static struct dt_mem_node_info mem_node;
Lijuan Gao9f152862014-08-18 13:45:24 +0800100static int platform_dt_absolute_match(struct dt_entry *cur_dt_entry, struct dt_entry_node *dt_list);
101static struct dt_entry *platform_dt_match_best(struct dt_entry_node *dt_list);
102static int update_dtb_entry_node(struct dt_entry_node *dt_list, uint32_t dtb_info);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700103extern int target_is_emmc_boot(void);
104extern uint32_t target_dev_tree_mem(void *fdt, uint32_t memory_node_offset);
Kishor PK536904a2017-07-13 17:18:59 +0530105static int update_fstab_node(void *fdt);
106
Deepa Dinamanic55f01b2013-05-30 14:05:56 -0700107/* TODO: This function needs to be moved to target layer to check violations
108 * against all the other regions as well.
109 */
Vijay Kumar Pendoti9c002ad2016-03-09 13:52:45 +0530110extern int check_aboot_addr_range_overlap(uintptr_t start, uint32_t size);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700111
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +0530112int fdt_check_header_ext(const void *fdt)
113{
114 uintptr_t fdt_start, fdt_end;
115 fdt_start = (uintptr_t)fdt;
116 if(fdt_start + fdt_totalsize(fdt) < fdt_start)
117 {
118 dprintf(CRITICAL,"Integer over in fdt header %s\t%d",__func__,__LINE__);
119 return FDT_ERR_BADOFFSET;
120 }
121 fdt_end = fdt_start + fdt_totalsize(fdt);
122
123 if (((uint64_t)fdt_start + (uint64_t)fdt_off_dt_struct(fdt) + (uint64_t)fdt_size_dt_struct(fdt)) > UINT_MAX)
124 return FDT_ERR_BADOFFSET;
125
126 if ((fdt_start + fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt)) > fdt_end)
127 return FDT_ERR_BADOFFSET;
128
129 if (((uint64_t)fdt_start + (uint64_t)fdt_off_dt_strings(fdt) + (uint64_t)fdt_size_dt_strings(fdt)) > UINT_MAX)
130 return FDT_ERR_BADOFFSET;
131
132 if ((fdt_start + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)) > fdt_end)
133 return FDT_ERR_BADOFFSET;
134
135 return 0;
136}
137
Shashank Mittalc0f10282013-07-15 14:53:31 -0700138/* Returns soc version if platform id and hardware id matches
139 otherwise return 0xFFFFFFFF */
140#define INVALID_SOC_REV_ID 0XFFFFFFFF
Lijuan Gao9f152862014-08-18 13:45:24 +0800141
142/* Add function to allocate dt entry list, used for recording
143* the entry which conform to platform_dt_absolute_match()
144*/
145static struct dt_entry_node *dt_entry_list_init(void)
146{
147 struct dt_entry_node *dt_node_member = NULL;
148
149 dt_node_member = (struct dt_entry_node *)
150 malloc(sizeof(struct dt_entry_node));
151
152 ASSERT(dt_node_member);
153
154 list_clear_node(&dt_node_member->node);
155 dt_node_member->dt_entry_m = (struct dt_entry *)
156 malloc(sizeof(struct dt_entry));
157 ASSERT(dt_node_member->dt_entry_m);
158
159 memset(dt_node_member->dt_entry_m ,0 ,sizeof(struct dt_entry));
160 return dt_node_member;
161}
162
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530163/*
164 * Function to validate dtbo image.
165 * return: TRUE or FALSE.
166 */
167dtbo_error load_validate_dtbo_image(void **dtbo_buf)
168{
169 uint64_t dtbo_total_size = 0;
170 void *dtbo_image_buf = NULL;
171 unsigned int dtbo_image_buf_size;
172 unsigned int dtbo_partition_size;
173 unsigned long long ptn, ptn_size, boot_img_sz;
174 int index = INVALID_PTN;
175 int page_size = mmc_page_size();
176 struct dtbo_table_hdr *dtbo_table_header = NULL;
177 dtbo_error ret = DTBO_SUCCESS;
178
179 /* Immediately return if dtbo is not supported */
180 index = partition_get_index("dtbo");
181 if (index == INVALID_PTN)
182 {
183 ret = DTBO_NOT_SUPPORTED;
184 goto out;
185 }
186
187 ptn = partition_get_offset(index);
188 if(!ptn)
189 {
190 dprintf(CRITICAL, "ERROR: dtbo parition failed to get offset. \n");
191 ret = DTBO_ERROR;
192 goto out;
193 }
194
195 ptn_size = partition_get_size(index);
196 if (ptn_size > DTBO_IMG_BUF)
197 {
198 dprintf(CRITICAL, "ERROR: dtbo parition size is greater than supported.\n");
199 ret = DTBO_ERROR;
200 goto out;
201 }
202
203/*
204 Read dtbo image into scratch region after kernel image.
205 dtbo_image_buf_size = total_scratch_region_size - boot_img_sz
206*/
207 boot_img_sz = partition_get_size(partition_get_index("boot"));
208 if (!boot_img_sz)
209 {
210 dprintf(CRITICAL, "ERROR: Unable to get boot partition size\n");
211 ret = DTBO_NOT_SUPPORTED;
212 goto out;
213 }
214
215 dtbo_image_buf_size = target_get_max_flash_size() - boot_img_sz;
216 dtbo_partition_size = ptn_size + ADDR_ALIGNMENT;
217 dtbo_partition_size = ROUND_TO_PAGE(dtbo_partition_size, (page_size - 1)); /* Maximum dtbo size possible */
218 if (dtbo_partition_size == UINT_MAX ||
219 dtbo_image_buf_size < dtbo_partition_size)
220 {
221 dprintf(CRITICAL, "ERROR: Invalid DTBO partition size\n");
222 ret = DTBO_NOT_SUPPORTED;
223 goto out;
224 }
225
226 mmc_set_lun(partition_get_lun(index));
227 dtbo_image_buf = target_get_scratch_address() + boot_img_sz; /* read dtbo after boot.img */
228 dtbo_image_buf = (void *)ROUND_TO_PAGE((addr_t)dtbo_image_buf, (ADDR_ALIGNMENT-1) );
229 if(dtbo_image_buf == (void *)UINT_MAX)
230 {
231 dprintf(CRITICAL, "ERROR: Invalid DTBO image buf addr\n");
232 ret = DTBO_NOT_SUPPORTED;
233 goto out;
234 }
235
236 /* Read dtbo partition with header */
237 if (mmc_read(ptn, (uint32_t *)(dtbo_image_buf), dtbo_partition_size))
238 {
239 dprintf(CRITICAL, "ERROR: dtbo partition mmc read failure \n");
240 ret = DTBO_ERROR;
241 goto out;
242 }
243
244 /* validate the dtbo image, before reading complete image */
245 dtbo_table_header = (struct dtbo_table_hdr *)dtbo_image_buf;
246
247 /*Check for dtbo magic*/
248 if (fdt32_to_cpu(dtbo_table_header->magic) != DTBO_TABLE_MAGIC)
249 {
250 dprintf(CRITICAL, "dtbo header magic mismatch %x, with %x\n",
251 fdt32_to_cpu(dtbo_table_header->magic), DTBO_TABLE_MAGIC);
252 ret = DTBO_ERROR;
253 goto out;
254 }
255
256 /*Check for dtbo image table size*/
257 if (fdt32_to_cpu(dtbo_table_header->hdr_size) != sizeof(struct dtbo_table_hdr))
258 {
259 dprintf(CRITICAL, "dtbo table header size got corrupted\n");
260 ret = DTBO_ERROR;
261 goto out;
262 }
263
264 /*Check for dt entry size of dtbo image*/
265 if (fdt32_to_cpu(dtbo_table_header->dt_entry_size) != sizeof(struct dtbo_table_entry))
266 {
267 dprintf(CRITICAL, "dtbo table dt entry size got corrupted\n");
268 ret = DTBO_ERROR;
269 goto out;
270 }
271
272 /*Total size of dtbo */
273 dtbo_total_size = fdt32_to_cpu(dtbo_table_header->total_size);
274 if (dtbo_total_size > dtbo_partition_size || dtbo_total_size == 0)
275 {
276 dprintf(CRITICAL, "dtbo table total size exceeded the dtbo buffer allocated\n");
277 ret = DTBO_ERROR;
278 goto out;
279 }
280
281 /* Total size of dtbo entries */
282 dtbo_total_size = fdt32_to_cpu(dtbo_table_header->dt_entry_count) *
283 fdt32_to_cpu(dtbo_table_header->dt_entry_size);
284 if (dtbo_total_size > dtbo_partition_size || dtbo_total_size == 0)
285 {
286 dprintf(CRITICAL, "dtbo table total size exceeded the dtbo buffer allocated\n");
287 ret = DTBO_ERROR;
288 goto out;
289 }
290
291 /* Offset should be less than image size */
292 if (fdt32_to_cpu(dtbo_table_header->dt_entry_offset) > dtbo_partition_size)
293 {
294 dprintf(CRITICAL, "dtbo offset exceeds the dtbo buffer allocated\n");
295 ret = DTBO_ERROR;
296 goto out;
297 }
298
299 /* Offset + total size is less than image size */
300 if (dtbo_total_size + fdt32_to_cpu(dtbo_table_header->dt_entry_offset) > dtbo_partition_size)
301 {
302 dprintf(CRITICAL, "dtbo size exceeded the dtbo buffer allocated\n");
303 ret = DTBO_ERROR;
304 }
305
306out:
307 *dtbo_buf = dtbo_image_buf;
308 return ret;
309}
310
311static bool check_all_bits_set(uint32_t matchdt_value)
312{
313 return (matchdt_value & ALL_BITS_SET) == (ALL_BITS_SET);
314}
315
316/* Dt selection table for quick reference
317 | SNO | Dt Property | CDT Property | Exact | Best | Default |
318 |-----+---------------+-----------------+-------+------+---------+
319 | | qcom, msm-id | | | | |
320 | | | PlatformId | Y | N | N |
321 | | | SocRev | N | Y | N |
322 | | | FoundryId | Y | N | 0 |
323 | | qcom,board-id | | | | |
324 | | | VariantId | Y | N | N |
325 | | | VariantMajor | N | Y | N |
326 | | | VariantMinor | N | Y | N |
327 | | | PlatformSubtype | Y | N | 0 |
328 | | qcom,pmic-id | | | | |
329 | | | PmicModelId | Y | N | 0 |
330 | | | PmicMetalRev | N | Y | N |
331 | | | PmicLayerRev | N | Y | N |
332 | | | PmicVariantRev | N | Y | N |
333*/
334
335static void dtb_read_find_match(dt_info *current_dtb_info, dt_info *best_dtb_info, uint32_t exact_match)
336{
337 int board_id_len;
338 int platform_id_len = 0;
339 int pmic_id_len;
340 int root_offset = 0;
341 void *dtb = current_dtb_info->dtb;
342 uint32_t idx;
343 const char *platform_prop = NULL;
344 const char *board_prop = NULL;
345 const char *pmic_prop = NULL;
346
347 current_dtb_info->dt_match_val = 0;
348 root_offset = fdt_path_offset(dtb, "/");
349 if (root_offset < 0) {
350 dprintf(CRITICAL, "ERROR: Unable to locate root node\n");
351 return;
352 }
353
354 /* Get the msm-id prop from DTB and find best match */
355 platform_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,msm-id", &platform_id_len);
356 if (platform_prop && (platform_id_len > 0) && (!(platform_id_len % PLAT_ID_SIZE))) {
357 /*Compare msm-id of the dtb vs board*/
358 current_dtb_info->dt_platform_id = fdt32_to_cpu(((struct plat_id *)platform_prop)->platform_id);
359 dprintf(SPEW, "Board SOC ID = %x | DT SOC ID = %x\n", (board_platform_id() & SOC_MASK),
360 (current_dtb_info->dt_platform_id & SOC_MASK));
361 if ((board_platform_id() & SOC_MASK) == (current_dtb_info->dt_platform_id & SOC_MASK)) {
362 current_dtb_info->dt_match_val |= BIT(SOC_MATCH);
363 } else {
364 dprintf(SPEW, "qcom,msm-id does not match\n");
365 /* If soc doesn't match, don't select dtb */
366 current_dtb_info->dt_match_val = BIT(NONE_MATCH);
367 goto cleanup;
368 }
369 /*Compare soc rev of the dtb vs board*/
370 current_dtb_info->dt_soc_rev = fdt32_to_cpu(((struct plat_id *)platform_prop)->soc_rev);
371 dprintf(SPEW, "Board SOC Rev = %x | DT SOC Rev =%x\n", board_soc_version(),
372 current_dtb_info->dt_soc_rev);
373 if (current_dtb_info->dt_soc_rev == board_soc_version()) {
374 current_dtb_info->dt_match_val |= BIT(VERSION_EXACT_MATCH);
375 } else if (current_dtb_info->dt_soc_rev < board_soc_version()) {
376 current_dtb_info->dt_match_val |= BIT(VERSION_BEST_MATCH);
377 } else if (current_dtb_info->dt_soc_rev) {
378 dprintf(SPEW, "SOC version does not match\n");
379 }
380 /*Compare Foundry Id of the dtb vs Board*/
381 current_dtb_info->dt_foundry_id = fdt32_to_cpu(((struct plat_id *)platform_prop)->platform_id) & FOUNDRY_ID_MASK;
382 dprintf (SPEW, "Board Foundry id = %x | DT Foundry id = %x\n", (board_foundry_id() << PLATFORM_FOUNDRY_SHIFT), current_dtb_info->dt_foundry_id);
383 if (current_dtb_info->dt_foundry_id == (board_foundry_id() << PLATFORM_FOUNDRY_SHIFT)) {
384 current_dtb_info->dt_match_val |= BIT (FOUNDRYID_EXACT_MATCH);
385 } else if (current_dtb_info->dt_foundry_id == 0 ){
386 current_dtb_info->dt_match_val |= BIT (FOUNDRYID_DEFAULT_MATCH);
387 } else {
388 dprintf(SPEW, "soc foundry does not match\n");
389 /* If soc doesn't match, don't select dtb */
390 current_dtb_info->dt_match_val = BIT(NONE_MATCH);
391 goto cleanup;
392 }
393 } else {
394 dprintf(SPEW, "qcom,msm-id does not exist (or) is (%d) not a multiple of (%d)\n", platform_id_len, PLAT_ID_SIZE);
395 }
396
397 /* Get the properties like variant id, subtype from DTB and compare the DTB vs Board */
398 board_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,board-id", &board_id_len);
399 if (board_prop && (board_id_len > 0) && (!(board_id_len % BOARD_ID_SIZE))) {
400 current_dtb_info->dt_variant_id = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id);
401 current_dtb_info->dt_platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->platform_subtype);
402 if (current_dtb_info->dt_platform_subtype == 0)
403 current_dtb_info->dt_platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id) >> PLATFORM_SUBTYPE_SHIFT_ID;
404
405 dprintf(SPEW, "Board variant id = %x | DT variant id = %x\n",board_hardware_id(), current_dtb_info->dt_variant_id);
406
407 current_dtb_info->dt_variant_major = current_dtb_info->dt_variant_id & VARIANT_MAJOR_MASK;
408 current_dtb_info->dt_variant_minor = current_dtb_info->dt_variant_id & VARIANT_MINOR_MASK;
409 current_dtb_info->dt_variant_id = current_dtb_info->dt_variant_id & VARIANT_MASK;
410
411 if (current_dtb_info->dt_variant_id == board_hardware_id()) {
412 current_dtb_info->dt_match_val |= BIT(VARIANT_MATCH);
413 } else if (current_dtb_info->dt_variant_id) {
414 dprintf(SPEW, "qcom,board-id doesnot match\n");
415 /* If board variant doesn't match, don't select dtb */
416 current_dtb_info->dt_match_val = BIT(NONE_MATCH);
417 goto cleanup;
418 }
419
420 if (current_dtb_info->dt_variant_major == (board_target_id() & VARIANT_MAJOR_MASK)) {
421 current_dtb_info->dt_match_val |= BIT(VARIANT_MAJOR_EXACT_MATCH);
422 } else if (current_dtb_info->dt_variant_major < (board_target_id() & VARIANT_MAJOR_MASK)) {
423 current_dtb_info->dt_match_val |= BIT(VARIANT_MAJOR_BEST_MATCH);
424 } else if (current_dtb_info->dt_variant_major) {
425 dprintf(SPEW, "qcom,board-id major version doesnot match\n");
426 }
427
428 if (current_dtb_info->dt_variant_minor == (board_target_id() & VARIANT_MINOR_MASK)) {
429 current_dtb_info->dt_match_val |= BIT(VARIANT_MINOR_EXACT_MATCH);
430 } else if (current_dtb_info->dt_variant_minor < (board_target_id() & VARIANT_MINOR_MASK)) {
431 current_dtb_info->dt_match_val |= BIT(VARIANT_MINOR_BEST_MATCH);
432 } else if (current_dtb_info->dt_variant_minor) {
433 dprintf(SPEW, "qcom,board-id minor version doesnot match\n");
434 }
435
436 dprintf(SPEW, "Board platform subtype = %x | DT platform subtype = %x\n",
437 board_hardware_subtype(), current_dtb_info->dt_platform_subtype);
438 if (current_dtb_info->dt_platform_subtype == board_hardware_subtype()) {
439 current_dtb_info->dt_match_val |= BIT(SUBTYPE_EXACT_MATCH);
440 } else if (current_dtb_info->dt_platform_subtype == 0) {
441 current_dtb_info->dt_match_val |= BIT(SUBTYPE_DEFAULT_MATCH);
442 } else if (current_dtb_info->dt_platform_subtype) {
443 dprintf(SPEW, "subtype id doesnot match\n");
444 /* If board platform doesn't match, don't select dtb */
445 current_dtb_info->dt_match_val = BIT(NONE_MATCH);
446 goto cleanup;
447 }
448 } else {
449 dprintf(SPEW, "qcom,board-id does not exist (or)(%d) is not a multiple of (%d)\n",
450 board_id_len, BOARD_ID_SIZE);
451 }
452
453 /* Get the pmic property from DTB then compare the DTB vs Board */
454 pmic_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,pmic-id", &pmic_id_len);
455 if (pmic_prop && (pmic_id_len > 0) && (!(pmic_id_len % sizeof(struct pmic_id))))
456 {
457 pmic_info curr_pmic_info;
458 pmic_info best_pmic_info;
459 unsigned int pmic_entry_indx;
460 unsigned int pmic_entries_count;
461
462 /* Find all pmic entries count */
463 pmic_entries_count = pmic_id_len/sizeof(struct pmic_id);
464
465 memset(&best_pmic_info, 0, sizeof(pmic_info));
466 for (pmic_entry_indx = 0; pmic_entry_indx < pmic_entries_count; pmic_entry_indx++)
467 {
468 memset(&curr_pmic_info, 0, sizeof(pmic_info));
469
470 /* Read all pmic info */
471 /* Compare with board pmic */
472 for (idx = 0; idx < MAX_PMIC_IDX; idx++)
473 {
474 curr_pmic_info.dt_pmic_model[idx] =
475 fdt32_to_cpu (((struct pmic_id *)pmic_prop)->pmic_version[idx]);
476 dprintf(SPEW, "pmic_data[%u]:%x\n", idx, curr_pmic_info.dt_pmic_model[idx]);
477 curr_pmic_info.dt_pmic_rev[idx] =
478 curr_pmic_info.dt_pmic_model[idx] & PMIC_REV_MASK;
479 curr_pmic_info.dt_pmic_model[idx] =
480 curr_pmic_info.dt_pmic_model[idx] & PMIC_MODEL_MASK;
481
482 /* Compare with board pmic information & Update bit mask */
483 if (curr_pmic_info.dt_pmic_model[idx] == (board_pmic_target(idx) & PMIC_MODEL_MASK))
484 curr_pmic_info.dt_match_val |= BIT (PMIC_MATCH_EXACT_MODEL_IDX0 + idx * PMIC_SHIFT_IDX);
485 else if (curr_pmic_info.dt_pmic_model[idx] == 0)
486 curr_pmic_info.dt_match_val |= BIT (PMIC_MATCH_DEFAULT_MODEL_IDX0 + idx * PMIC_SHIFT_IDX);
487 else
488 {
489 curr_pmic_info.dt_match_val |= BIT (NONE_MATCH);
490 dprintf(SPEW, "PMIC Model doesn't match\n");
491 break; /* go to next pmic entry */
492 }
493
494 if (curr_pmic_info.dt_pmic_rev[idx] == (board_pmic_target(idx) & PMIC_REV_MASK))
495 curr_pmic_info.dt_match_val |= BIT(PMIC_MATCH_EXACT_REV_IDX0 + idx * PMIC_SHIFT_IDX);
496 else if (curr_pmic_info.dt_pmic_rev[idx] < (board_pmic_target(idx) & PMIC_REV_MASK))
497 curr_pmic_info.dt_match_val |= BIT(PMIC_MATCH_BEST_REV_IDX0 + idx * PMIC_SHIFT_IDX);
498 else
499 dprintf(SPEW, "PMIC revision doesn't match\n");
500 break; /* go to next pmic entry */
501 }
502
503 dprintf(SPEW, "Bestpmicinfo.dtmatchval : %x | cur_pmic_info.dtmatchval: %x\n",
504 best_pmic_info.dt_match_val, curr_pmic_info.dt_match_val);
505
506 /* Update best pmic info, if required */
507 if(best_pmic_info.dt_match_val < curr_pmic_info.dt_match_val)
508 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
509 else if (best_pmic_info.dt_match_val == curr_pmic_info.dt_match_val)
510 {
511 if (best_pmic_info.dt_pmic_rev[PMIC_IDX0] < curr_pmic_info.dt_pmic_rev[PMIC_IDX0])
512 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
513 else if (best_pmic_info.dt_pmic_rev[PMIC_IDX1] < curr_pmic_info.dt_pmic_rev[PMIC_IDX1])
514 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
515 else if (best_pmic_info.dt_pmic_rev[PMIC_IDX2] < curr_pmic_info.dt_pmic_rev[PMIC_IDX2])
516 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
517 else if (best_pmic_info.dt_pmic_rev[PMIC_IDX3] < curr_pmic_info.dt_pmic_rev[PMIC_IDX3])
518 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
519 }
520
521 /* Increment to next pmic entry */
522 pmic_prop += sizeof (struct pmic_id);
523 }
524
525 dprintf(SPEW, "Best pmic info 0x%0x/0x%x/0x%x/0x%0x for current dt\n",
526 best_pmic_info.dt_pmic_model[PMIC_IDX0],
527 best_pmic_info.dt_pmic_model[PMIC_IDX1],
528 best_pmic_info.dt_pmic_model[PMIC_IDX2],
529 best_pmic_info.dt_pmic_model[PMIC_IDX3]);
530
531 current_dtb_info->dt_match_val |= best_pmic_info.dt_match_val;
532 current_dtb_info->dt_pmic_rev[PMIC_IDX0] = best_pmic_info.dt_pmic_rev[PMIC_IDX0];
533 current_dtb_info->dt_pmic_model[PMIC_IDX0] = best_pmic_info.dt_pmic_model[PMIC_IDX0];
534 current_dtb_info->dt_pmic_rev[PMIC_IDX1] = best_pmic_info.dt_pmic_rev[PMIC_IDX1];
535 current_dtb_info->dt_pmic_model[PMIC_IDX1] = best_pmic_info.dt_pmic_model[PMIC_IDX1];
536 current_dtb_info->dt_pmic_rev[PMIC_IDX2] = best_pmic_info.dt_pmic_rev[PMIC_IDX2];
537 current_dtb_info->dt_pmic_model[PMIC_IDX2] = best_pmic_info.dt_pmic_model[PMIC_IDX2];
538 current_dtb_info->dt_pmic_rev[PMIC_IDX3] = best_pmic_info.dt_pmic_rev[PMIC_IDX3];
539 current_dtb_info->dt_pmic_model[PMIC_IDX3] = best_pmic_info.dt_pmic_model[PMIC_IDX3];
540 }
541 else
542 {
543 dprintf(SPEW, "qcom,pmic-id does not exit (or) is (%d) not a multiple of (%d)\n",
544 pmic_id_len, PMIC_ID_SIZE);
545 }
546
547cleanup:
548 if (current_dtb_info->dt_match_val & BIT(exact_match)) {
549 if (best_dtb_info->dt_match_val < current_dtb_info->dt_match_val)
550 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
551 else if (best_dtb_info->dt_match_val == current_dtb_info->dt_match_val) {
552 if (best_dtb_info->dt_soc_rev < current_dtb_info->dt_soc_rev)
553 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
554 else if (best_dtb_info->dt_variant_major < current_dtb_info->dt_variant_major)
555 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
556 else if (best_dtb_info->dt_variant_minor < current_dtb_info->dt_variant_minor)
557 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
558 else if (best_dtb_info->dt_pmic_rev[0] < current_dtb_info->dt_pmic_rev[0])
559 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
560 else if (best_dtb_info->dt_pmic_rev[1] < current_dtb_info->dt_pmic_rev[1])
561 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
562 else if (best_dtb_info->dt_pmic_rev[2] < current_dtb_info->dt_pmic_rev[2])
563 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
564 else if (best_dtb_info->dt_pmic_rev[3] < current_dtb_info->dt_pmic_rev[3])
565 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
566 }
567 }
568}
569
570void *get_soc_dtb(void *kernel, uint32_t kernel_size, uint32_t dtb_offset)
571{
572 uintptr_t kernel_end_offset = (uintptr_t)kernel + kernel_size;
573 void *dtb = NULL;
574 struct fdt_header dtb_header;
575 uint32_t dtb_size = 0;
576 dt_info cur_dtb_info = {0};
577 dt_info best_dtb_info = {0};
578
579 if (!dtb_offset){
580 dprintf(CRITICAL, "DTB offset is NULL\n");
581 return NULL;
582 }
583 if (((uintptr_t)kernel + (uintptr_t)dtb_offset) < (uintptr_t)kernel) {
584 return NULL;
585 }
586 dtb = kernel + dtb_offset;
587 while (((uintptr_t)dtb + sizeof(struct fdt_header)) < (uintptr_t)kernel_end_offset) {
588 /* the DTB could be unaligned, so extract the header,
589 * and operate on it separately */
590 memscpy(&dtb_header, sizeof(struct fdt_header), dtb, sizeof(struct fdt_header));
591 dtb_size = fdt_totalsize((const void *)&dtb_header);
592 if (fdt_check_header((const void *)&dtb_header) != 0 ||
593 fdt_check_header_ext((void *)&dtb_header) != 0 ||
594 ((uintptr_t)dtb + dtb_size < (uintptr_t)dtb) ||
595 ((uintptr_t)dtb + dtb_size > (uintptr_t)kernel_end_offset))
596 break;
597
598 cur_dtb_info.dtb = dtb;
599 dtb_read_find_match(&cur_dtb_info, &best_dtb_info, SOC_MATCH);
600 if (cur_dtb_info.dt_match_val) {
601 if (cur_dtb_info.dt_match_val & BIT(SOC_MATCH)) {
602 if (check_all_bits_set(cur_dtb_info.dt_match_val)) {
603 dprintf(CRITICAL, "Exact DTB match found. dtbo search is not required\n");
604 dtbo_needed = false;
605 }
606 }
607 }
608 dprintf(SPEW, "Best Match DTB VAL = %x\n", best_dtb_info.dt_match_val);
609 dtb += dtb_size;
610 }
611 if (!best_dtb_info.dtb) {
612 dprintf(CRITICAL, "No match found for soc dtb type\n");
613 return NULL;
614 }
615 return best_dtb_info.dtb;
616}
617
618void *get_board_dtb(void *dtbo_image_buf)
619{
620 struct dtbo_table_hdr *dtbo_table_header = dtbo_image_buf;
621 struct dtbo_table_entry *dtb_table_entry = NULL;
622 uint32_t dtbo_count = 0;
623 void *board_dtb = NULL;
624 uint32_t dtbo_table_entries_count = 0;
625 uint32_t first_dtbo_table_entry_offset = 0;
626 struct fdt_header dtb_header;
627 uint32_t dtb_size = 0;
628 dt_info cur_dtb_info = {0};
629 dt_info best_dtb_info = {0};
630
631 if (!dtbo_image_buf) {
632 dprintf(CRITICAL, "dtbo image buffer is NULL\n");
633 return NULL;
634 }
635
636 first_dtbo_table_entry_offset = fdt32_to_cpu(dtbo_table_header->dt_entry_offset);
637 if ((uintptr_t)dtbo_image_buf > ((uintptr_t)dtbo_image_buf + (uintptr_t)first_dtbo_table_entry_offset))
638 {
639 dprintf(CRITICAL, "dtbo table entry offset is invalid\n");
640 return NULL;
641 }
642 dtb_table_entry = (struct dtbo_table_entry *)(dtbo_image_buf + first_dtbo_table_entry_offset);
643 dtbo_table_entries_count = fdt32_to_cpu(dtbo_table_header->dt_entry_count);
644 for (dtbo_count = 0; dtbo_count < dtbo_table_entries_count; dtbo_count++) {
645 board_dtb = dtbo_image_buf + fdt32_to_cpu(dtb_table_entry->dt_offset);
646 /* The DTB could be unaligned, so extract the header,
647 * and operate on it separately */
648 memscpy(&dtb_header, sizeof(struct fdt_header), board_dtb, sizeof(struct fdt_header));
649 dtb_size = fdt_totalsize((const void *)&dtb_header);
650 if (fdt_check_header((const void *)&dtb_header) != 0 ||
651 fdt_check_header_ext((void *)&dtb_header) != 0 ||
652 ((uintptr_t)board_dtb + dtb_size < (uintptr_t)board_dtb)) {
653 dprintf(CRITICAL, "No valid board dtb found\n");
654 break;
655 }
656 dprintf(SPEW, "Valid board dtb is found\n");
657 cur_dtb_info.dtb = board_dtb;
658 dtb_read_find_match(&cur_dtb_info, &best_dtb_info, VARIANT_MATCH);
659 dprintf(SPEW, "dtbo count = %u local_board_dt_match =%x\n",dtbo_count, cur_dtb_info.dt_match_val);
660 dtb_table_entry++;
661 }
662 if (!best_dtb_info.dtb) {
663 dprintf(CRITICAL, "Unable to find the board dtb\n");
664 return NULL;
665 }
666 return best_dtb_info.dtb;
667}
668
Lijuan Gao9f152862014-08-18 13:45:24 +0800669static void insert_dt_entry_in_queue(struct dt_entry_node *dt_list, struct dt_entry_node *dt_node_member)
670{
671 list_add_tail(&dt_list->node, &dt_node_member->node);
672}
673
674static void dt_entry_list_delete(struct dt_entry_node *dt_node_member)
675{
676 if (list_in_list(&dt_node_member->node)) {
677 list_delete(&dt_node_member->node);
678 free(dt_node_member->dt_entry_m);
679 free(dt_node_member);
680 }
681}
682
683static int dev_tree_compatible(void *dtb, uint32_t dtb_size, struct dt_entry_node *dtb_list)
Dima Zavinc46f8382013-05-03 12:23:06 -0700684{
685 int root_offset;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700686 const void *prop = NULL;
687 const char *plat_prop = NULL;
688 const char *board_prop = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800689 const char *pmic_prop = NULL;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700690 char *model = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800691 struct dt_entry *cur_dt_entry;
692 struct dt_entry *dt_entry_array = NULL;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700693 struct board_id *board_data = NULL;
694 struct plat_id *platform_data = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800695 struct pmic_id *pmic_data = NULL;
Dima Zavinc46f8382013-05-03 12:23:06 -0700696 int len;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700697 int len_board_id;
698 int len_plat_id;
699 int min_plat_id_len = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800700 int len_pmic_id;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700701 uint32_t dtb_ver;
702 uint32_t num_entries = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800703 uint32_t i, j, k, n;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700704 uint32_t msm_data_count;
705 uint32_t board_data_count;
Lijuan Gao9f152862014-08-18 13:45:24 +0800706 uint32_t pmic_data_count;
Dima Zavinc46f8382013-05-03 12:23:06 -0700707
708 root_offset = fdt_path_offset(dtb, "/");
709 if (root_offset < 0)
710 return false;
711
712 prop = fdt_getprop(dtb, root_offset, "model", &len);
713 if (prop && len > 0) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700714 model = (char *) malloc(sizeof(char) * len);
715 ASSERT(model);
716 strlcpy(model, prop, len);
Dima Zavinc46f8382013-05-03 12:23:06 -0700717 } else {
vijay kumar89d36d82014-06-30 19:32:18 +0530718 dprintf(INFO, "model does not exist in device tree\n");
Dima Zavinc46f8382013-05-03 12:23:06 -0700719 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800720 /* Find the pmic-id prop from DTB , if pmic-id is present then
721 * the DTB is version 3, otherwise find the board-id prop from DTB ,
722 * if board-id is present then the DTB is version 2 */
723 pmic_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,pmic-id", &len_pmic_id);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700724 board_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,board-id", &len_board_id);
Lijuan Gao9f152862014-08-18 13:45:24 +0800725 if (pmic_prop && (len_pmic_id > 0) && board_prop && (len_board_id > 0)) {
726 if ((len_pmic_id % PMIC_ID_SIZE) || (len_board_id % BOARD_ID_SIZE))
727 {
728 dprintf(CRITICAL, "qcom,pmic-id(%d) or qcom,board-id(%d) in device tree is not a multiple of (%d %d)\n",
729 len_pmic_id, len_board_id, PMIC_ID_SIZE, BOARD_ID_SIZE);
730 return false;
731 }
732 dtb_ver = DEV_TREE_VERSION_V3;
733 min_plat_id_len = PLAT_ID_SIZE;
734 } else if (board_prop && len_board_id > 0) {
vijay kumar89d36d82014-06-30 19:32:18 +0530735 if (len_board_id % BOARD_ID_SIZE)
736 {
737 dprintf(CRITICAL, "qcom,board-id in device tree is (%d) not a multiple of (%d)\n",
738 len_board_id, BOARD_ID_SIZE);
739 return false;
740 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700741 dtb_ver = DEV_TREE_VERSION_V2;
742 min_plat_id_len = PLAT_ID_SIZE;
Lijuan Gao9f152862014-08-18 13:45:24 +0800743 } else {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700744 dtb_ver = DEV_TREE_VERSION_V1;
745 min_plat_id_len = DT_ENTRY_V1_SIZE;
746 }
747
748 /* Get the msm-id prop from DTB */
749 plat_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,msm-id", &len_plat_id);
750 if (!plat_prop || len_plat_id <= 0) {
Dima Zavinc46f8382013-05-03 12:23:06 -0700751 dprintf(INFO, "qcom,msm-id entry not found\n");
752 return false;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700753 } else if (len_plat_id % min_plat_id_len) {
754 dprintf(INFO, "qcom,msm-id in device tree is (%d) not a multiple of (%d)\n",
755 len_plat_id, min_plat_id_len);
Dima Zavinc46f8382013-05-03 12:23:06 -0700756 return false;
757 }
Dima Zavinc46f8382013-05-03 12:23:06 -0700758
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700759 /*
760 * If DTB version is '1' look for <x y z> pair in the DTB
761 * x: platform_id
762 * y: variant_id
763 * z: SOC rev
764 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800765 if (dtb_ver == DEV_TREE_VERSION_V1) {
766 cur_dt_entry = (struct dt_entry *)
767 malloc(sizeof(struct dt_entry));
Dima Zavinc46f8382013-05-03 12:23:06 -0700768
Lijuan Gao9f152862014-08-18 13:45:24 +0800769 if (!cur_dt_entry) {
770 dprintf(CRITICAL, "Out of memory\n");
771 return false;
772 }
773 memset(cur_dt_entry, 0, sizeof(struct dt_entry));
774
775 while (len_plat_id) {
776 cur_dt_entry->platform_id = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->platform_id);
777 cur_dt_entry->variant_id = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->variant_id);
778 cur_dt_entry->soc_rev = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->soc_rev);
779 cur_dt_entry->board_hw_subtype =
780 fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->variant_id) >> 0x18;
781 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
782 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
783 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
784 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
785 cur_dt_entry->offset = (uint32_t)dtb;
786 cur_dt_entry->size = dtb_size;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700787
788 dprintf(SPEW, "Found an appended flattened device tree (%s - %u %u 0x%x)\n",
Lijuan Gao9f152862014-08-18 13:45:24 +0800789 *model ? model : "unknown",
790 cur_dt_entry->platform_id, cur_dt_entry->variant_id, cur_dt_entry->soc_rev);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700791
Lijuan Gao9f152862014-08-18 13:45:24 +0800792 if (platform_dt_absolute_match(cur_dt_entry, dtb_list)) {
793 dprintf(SPEW, "Device tree exact match the board: <%u %u 0x%x> != <%u %u 0x%x>\n",
794 cur_dt_entry->platform_id,
795 cur_dt_entry->variant_id,
796 cur_dt_entry->soc_rev,
797 board_platform_id(),
798 board_hardware_id(),
799 board_soc_version());
800
801 } else {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700802 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 +0800803 cur_dt_entry->platform_id,
804 cur_dt_entry->variant_id,
805 cur_dt_entry->soc_rev,
806 board_platform_id(),
807 board_hardware_id(),
808 board_soc_version());
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700809 plat_prop += DT_ENTRY_V1_SIZE;
810 len_plat_id -= DT_ENTRY_V1_SIZE;
811 continue;
812 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700813 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800814 free(cur_dt_entry);
815
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700816 }
817 /*
Lijuan Gao9f152862014-08-18 13:45:24 +0800818 * If DTB Version is '3' then we have split DTB with board & msm data & pmic
819 * populated saperately in board-id & msm-id & pmic-id prop respectively.
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700820 * Extract the data & prepare a look up table
821 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800822 else if (dtb_ver == DEV_TREE_VERSION_V2 || dtb_ver == DEV_TREE_VERSION_V3) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700823 board_data_count = (len_board_id / BOARD_ID_SIZE);
824 msm_data_count = (len_plat_id / PLAT_ID_SIZE);
Lijuan Gao9f152862014-08-18 13:45:24 +0800825 /* If dtb version is v2.0, the pmic_data_count will be <= 0 */
826 pmic_data_count = (len_pmic_id / PMIC_ID_SIZE);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700827
Lijuan Gao9f152862014-08-18 13:45:24 +0800828 /* If we are using dtb v3.0, then we have split board, msm & pmic data in the DTB
829 * If we are using dtb v2.0, then we have split board & msmdata in the DTB
830 */
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700831 board_data = (struct board_id *) malloc(sizeof(struct board_id) * (len_board_id / BOARD_ID_SIZE));
832 ASSERT(board_data);
833 platform_data = (struct plat_id *) malloc(sizeof(struct plat_id) * (len_plat_id / PLAT_ID_SIZE));
834 ASSERT(platform_data);
Lijuan Gao9f152862014-08-18 13:45:24 +0800835 if (dtb_ver == DEV_TREE_VERSION_V3) {
836 pmic_data = (struct pmic_id *) malloc(sizeof(struct pmic_id) * (len_pmic_id / PMIC_ID_SIZE));
837 ASSERT(pmic_data);
838 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700839 i = 0;
840
841 /* Extract board data from DTB */
Lijuan Gao9f152862014-08-18 13:45:24 +0800842 for(i = 0 ; i < board_data_count; i++) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700843 board_data[i].variant_id = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id);
844 board_data[i].platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->platform_subtype);
Lijuan Gao9f152862014-08-18 13:45:24 +0800845 /* For V2/V3 version of DTBs we have platform version field as part
846 * of variant ID, in such case the subtype will be mentioned as 0x0
847 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
848 * SS -- Subtype
849 * PM -- Platform major version
850 * Pm -- Platform minor version
851 * PH -- Platform hardware CDP/MTP
852 * In such case to make it compatible with LK algorithm move the subtype
853 * from variant_id to subtype field
854 */
855 if (board_data[i].platform_subtype == 0)
856 board_data[i].platform_subtype =
857 fdt32_to_cpu(((struct board_id *)board_prop)->variant_id) >> 0x18;
858
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700859 len_board_id -= sizeof(struct board_id);
860 board_prop += sizeof(struct board_id);
861 }
862
863 /* Extract platform data from DTB */
Lijuan Gao9f152862014-08-18 13:45:24 +0800864 for(i = 0 ; i < msm_data_count; i++) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700865 platform_data[i].platform_id = fdt32_to_cpu(((struct plat_id *)plat_prop)->platform_id);
866 platform_data[i].soc_rev = fdt32_to_cpu(((struct plat_id *)plat_prop)->soc_rev);
867 len_plat_id -= sizeof(struct plat_id);
868 plat_prop += sizeof(struct plat_id);
869 }
870
Lijuan Gao9f152862014-08-18 13:45:24 +0800871 if (dtb_ver == DEV_TREE_VERSION_V3 && pmic_prop) {
872 /* Extract pmic data from DTB */
873 for(i = 0 ; i < pmic_data_count; i++) {
874 pmic_data[i].pmic_version[0]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[0]);
875 pmic_data[i].pmic_version[1]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[1]);
876 pmic_data[i].pmic_version[2]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[2]);
877 pmic_data[i].pmic_version[3]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[3]);
878 len_pmic_id -= sizeof(struct pmic_id);
879 pmic_prop += sizeof(struct pmic_id);
880 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700881
Lijuan Gao9f152862014-08-18 13:45:24 +0800882 /* We need to merge board & platform data into dt entry structure */
883 num_entries = msm_data_count * board_data_count * pmic_data_count;
884 } else {
885 /* We need to merge board & platform data into dt entry structure */
886 num_entries = msm_data_count * board_data_count;
887 }
vijay kumar89d36d82014-06-30 19:32:18 +0530888
Lijuan Gao9f152862014-08-18 13:45:24 +0800889 if ((((uint64_t)msm_data_count * (uint64_t)board_data_count * (uint64_t)pmic_data_count) !=
890 msm_data_count * board_data_count * pmic_data_count) ||
891 (((uint64_t)msm_data_count * (uint64_t)board_data_count) != msm_data_count * board_data_count)) {
892
893 free(board_data);
894 free(platform_data);
895 if (pmic_data)
896 free(pmic_data);
897 if (model)
898 free(model);
899 return false;
900 }
901
902 dt_entry_array = (struct dt_entry*) malloc(sizeof(struct dt_entry) * num_entries);
903 ASSERT(dt_entry_array);
904
905 /* If we have '<X>; <Y>; <Z>' as platform data & '<A>; <B>; <C>' as board data.
906 * Then dt entry should look like
907 * <X ,A >;<X, B>;<X, C>;
908 * <Y ,A >;<Y, B>;<Y, C>;
909 * <Z ,A >;<Z, B>;<Z, C>;
910 */
911 i = 0;
912 k = 0;
913 n = 0;
914 for (i = 0; i < msm_data_count; i++) {
915 for (j = 0; j < board_data_count; j++) {
916 if (dtb_ver == DEV_TREE_VERSION_V3 && pmic_prop) {
917 for (n = 0; n < pmic_data_count; n++) {
918 dt_entry_array[k].platform_id = platform_data[i].platform_id;
919 dt_entry_array[k].soc_rev = platform_data[i].soc_rev;
920 dt_entry_array[k].variant_id = board_data[j].variant_id;
921 dt_entry_array[k].board_hw_subtype = board_data[j].platform_subtype;
922 dt_entry_array[k].pmic_rev[0]= pmic_data[n].pmic_version[0];
923 dt_entry_array[k].pmic_rev[1]= pmic_data[n].pmic_version[1];
924 dt_entry_array[k].pmic_rev[2]= pmic_data[n].pmic_version[2];
925 dt_entry_array[k].pmic_rev[3]= pmic_data[n].pmic_version[3];
926 dt_entry_array[k].offset = (uint32_t)dtb;
927 dt_entry_array[k].size = dtb_size;
928 k++;
929 }
930
931 } else {
932 dt_entry_array[k].platform_id = platform_data[i].platform_id;
933 dt_entry_array[k].soc_rev = platform_data[i].soc_rev;
934 dt_entry_array[k].variant_id = board_data[j].variant_id;
935 dt_entry_array[k].board_hw_subtype = board_data[j].platform_subtype;
936 dt_entry_array[k].pmic_rev[0]= board_pmic_target(0);
937 dt_entry_array[k].pmic_rev[1]= board_pmic_target(1);
938 dt_entry_array[k].pmic_rev[2]= board_pmic_target(2);
939 dt_entry_array[k].pmic_rev[3]= board_pmic_target(3);
940 dt_entry_array[k].offset = (uint32_t)dtb;
941 dt_entry_array[k].size = dtb_size;
vijay kumar89d36d82014-06-30 19:32:18 +0530942 k++;
943 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700944 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800945 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700946
Lijuan Gao9f152862014-08-18 13:45:24 +0800947 for (i=0 ;i < num_entries; i++) {
948 dprintf(SPEW, "Found an appended flattened device tree (%s - %u %u %u 0x%x)\n",
949 *model ? model : "unknown",
950 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 +0530951
Lijuan Gao9f152862014-08-18 13:45:24 +0800952 if (platform_dt_absolute_match(&(dt_entry_array[i]), dtb_list)) {
953 dprintf(SPEW, "Device tree exact match the board: <%u %u %u 0x%x> == <%u %u %u 0x%x>\n",
954 dt_entry_array[i].platform_id,
955 dt_entry_array[i].variant_id,
956 dt_entry_array[i].soc_rev,
957 dt_entry_array[i].board_hw_subtype,
958 board_platform_id(),
959 board_hardware_id(),
960 board_hardware_subtype(),
961 board_soc_version());
vijay kumar89d36d82014-06-30 19:32:18 +0530962
Lijuan Gao9f152862014-08-18 13:45:24 +0800963 } else {
964 dprintf(SPEW, "Device tree's msm_id doesn't match the board: <%u %u %u 0x%x> != <%u %u %u 0x%x>\n",
965 dt_entry_array[i].platform_id,
966 dt_entry_array[i].variant_id,
967 dt_entry_array[i].soc_rev,
968 dt_entry_array[i].board_hw_subtype,
969 board_platform_id(),
970 board_hardware_id(),
971 board_hardware_subtype(),
972 board_soc_version());
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700973 }
974 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800975
976 free(board_data);
977 free(platform_data);
978 if (pmic_data)
979 free(pmic_data);
980 free(dt_entry_array);
Dima Zavinc46f8382013-05-03 12:23:06 -0700981 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800982 if (model)
vijay kumar89d36d82014-06-30 19:32:18 +0530983 free(model);
Lijuan Gao9f152862014-08-18 13:45:24 +0800984 return true;
Dima Zavinc46f8382013-05-03 12:23:06 -0700985}
986
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530987/* function to handle the overlay in independent thread */
988static int dtb_overlay_handler(void *args)
989{
990 dprintf(SPEW, "thread %s() started\n", __func__);
991
992 soc_dtb_hdr = ufdt_install_blob(soc_dtb, fdt_totalsize(soc_dtb));
993 if(!soc_dtb_hdr)
994 {
995 dprintf(CRITICAL, "ERROR: Install Blob failed\n");
996 ret = DTBO_ERROR;
997 goto out;
998 }
999 final_dtb_hdr = ufdt_apply_overlay(soc_dtb_hdr, fdt_totalsize(soc_dtb_hdr),board_dtb,
1000 fdt_totalsize(board_dtb));
1001 if (!final_dtb_hdr)
1002 {
1003 dprintf(CRITICAL, "ERROR: UFDT apply overlay failed\n");
1004 ret = DTBO_ERROR;
1005 goto out;
1006 }
1007out:
1008 /* This flag can only be updated here, hence it is not protected */
1009 event_signal(&dtbo_event, true);
1010 thread_exit(0);
1011 return 0;
1012}
1013
1014/*
1015 * Function to check and form new dtb with Overlay support.
1016*/
1017dtbo_error dev_tree_appended_with_dtbo(void *kernel, uint32_t kernel_size,
1018 uint32_t dtb_offset, void *tags)
1019{
1020 void *dtbo_image_buf = NULL;
1021
Mayank Grover302432a2017-12-08 17:18:58 +05301022 bs_set_timestamp(BS_DTB_OVERLAY_START);
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301023 ret = load_validate_dtbo_image(&dtbo_image_buf);
1024 if (ret == DTBO_SUCCESS)
1025 {
1026 final_dtb_hdr = soc_dtb = get_soc_dtb(kernel,
1027 kernel_size, dtb_offset);
1028 if(!soc_dtb)
1029 {
1030 ret = DTBO_ERROR;
1031 goto out;
1032 }
1033
1034 if (dtbo_needed)
1035 {
1036 board_dtb = get_board_dtb(dtbo_image_buf);
1037 if(!board_dtb)
1038 {
1039 ret = DTBO_ERROR;
1040 goto out;
1041 }
1042
1043 if((ADD_OF((fdt_totalsize(soc_dtb)), (fdt_totalsize(board_dtb)))) > MAX_DTBO_SZ)
1044 {
1045 dprintf(CRITICAL, "ERROR: dtb greater than max supported.\n");
1046 ret = DTBO_ERROR;
1047 goto out;
1048 }
1049
1050 /*
1051 spawn a seperate thread for dtbo overlay with indpendent,
1052 stack to avoid issues with stack corruption seen during flattening,
1053 of dtb in overlay functionality
1054 */
1055 {
1056 thread_t *thr = NULL;
1057 event_init(&dtbo_event, 0, EVENT_FLAG_AUTOUNSIGNAL);
1058 thr = thread_create("dtb_overlay", dtb_overlay_handler, 0,
1059 DEFAULT_PRIORITY, DTBO_STACK_SIZE);
1060 if (!thr)
1061 {
1062 dprintf(CRITICAL, "ERROR: Failed to create DTBO thread.\n");
1063 ret = DTBO_ERROR;
1064 goto out;
1065 }
1066 thread_resume(thr);
1067
1068 /* block current thread, untill woken up by dtb_overlay_handler. */
1069 event_wait(&dtbo_event);
1070
1071 /* ret is updated by dtb overlay thread, in case of error */
1072 if(ret == DTBO_ERROR)
1073 {
1074 goto out;
1075 }
1076 } /* dtbo_overlay_handler exited */
1077
1078 }
1079 memscpy(tags, fdt_totalsize(final_dtb_hdr), final_dtb_hdr,
1080 fdt_totalsize(final_dtb_hdr));
1081 dprintf(CRITICAL, "DTB overlay is successful\n");
1082 }
1083 else
1084 {
1085 dprintf(CRITICAL, "ERROR: DTBO read is not valid\n DTB Overlay failed.\n");
1086 ret = DTBO_NOT_SUPPORTED;
1087 }
1088out:
Mayank Grover302432a2017-12-08 17:18:58 +05301089 bs_set_timestamp(BS_DTB_OVERLAY_END);
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301090 return ret;
1091}
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001092/*
Dima Zavin77e41f32013-03-06 16:10:43 -08001093 * Will relocate the DTB to the tags addr if the device tree is found and return
1094 * its address
1095 *
1096 * Arguments: kernel - Start address of the kernel loaded in RAM
1097 * tags - Start address of the tags loaded in RAM
Channagoud Kadabi704cd562013-04-25 15:19:59 -07001098 * kernel_size - Size of the kernel in bytes
1099 *
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001100 * Return Value: DTB address : If appended device tree is found
Dima Zavin77e41f32013-03-06 16:10:43 -08001101 * 'NULL' : Otherwise
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001102 */
Matthew Qinbb7923d2015-02-09 10:56:09 +08001103void *dev_tree_appended(void *kernel, uint32_t kernel_size, uint32_t dtb_offset, void *tags)
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001104{
Parth Dixit97e47bb2016-03-07 17:20:44 +05301105 uintptr_t kernel_end = (uintptr_t)kernel + kernel_size;
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001106 uint32_t app_dtb_offset = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +08001107 void *dtb = NULL;
Shashank Mittalc0f10282013-07-15 14:53:31 -07001108 void *bestmatch_tag = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +08001109 struct dt_entry *best_match_dt_entry = NULL;
Shashank Mittalc0f10282013-07-15 14:53:31 -07001110 uint32_t bestmatch_tag_size;
Lijuan Gao9f152862014-08-18 13:45:24 +08001111 struct dt_entry_node *dt_entry_queue = NULL;
1112 struct dt_entry_node *dt_node_tmp1 = NULL;
1113 struct dt_entry_node *dt_node_tmp2 = NULL;
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301114 dtbo_error ret = DTBO_NOT_SUPPORTED;
1115
1116 /* Check for dtbo support */
1117 ret = dev_tree_appended_with_dtbo(kernel, kernel_size, dtb_offset, tags);
1118 if (ret == DTBO_SUCCESS)
1119 return tags;
1120 else if (ret == DTBO_ERROR)
1121 return NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +08001122
Lijuan Gao9f152862014-08-18 13:45:24 +08001123 /* Initialize the dtb entry node*/
1124 dt_entry_queue = (struct dt_entry_node *)
1125 malloc(sizeof(struct dt_entry_node));
1126
1127 if (!dt_entry_queue) {
1128 dprintf(CRITICAL, "Out of memory\n");
1129 return NULL;
1130 }
1131 list_initialize(&dt_entry_queue->node);
1132
Matthew Qinbb7923d2015-02-09 10:56:09 +08001133 if (dtb_offset)
1134 app_dtb_offset = dtb_offset;
1135 else
1136 memcpy((void*) &app_dtb_offset, (void*) (kernel + DTB_OFFSET), sizeof(uint32_t));
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001137
vijay kumare2a5ea82014-06-25 12:24:14 +05301138 if (((uintptr_t)kernel + (uintptr_t)app_dtb_offset) < (uintptr_t)kernel) {
1139 return NULL;
1140 }
Parth Dixit97e47bb2016-03-07 17:20:44 +05301141 dtb = (void *)((uintptr_t)kernel + app_dtb_offset);
1142
vijay kumare2a5ea82014-06-25 12:24:14 +05301143 while (((uintptr_t)dtb + sizeof(struct fdt_header)) < (uintptr_t)kernel_end) {
Dima Zavinc46f8382013-05-03 12:23:06 -07001144 struct fdt_header dtb_hdr;
1145 uint32_t dtb_size;
Dima Zavin77e41f32013-03-06 16:10:43 -08001146
Dima Zavinc46f8382013-05-03 12:23:06 -07001147 /* the DTB could be unaligned, so extract the header,
1148 * and operate on it separately */
1149 memcpy(&dtb_hdr, dtb, sizeof(struct fdt_header));
1150 if (fdt_check_header((const void *)&dtb_hdr) != 0 ||
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +05301151 fdt_check_header_ext((const void *)&dtb_hdr) != 0 ||
vijay kumare2a5ea82014-06-25 12:24:14 +05301152 ((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) < (uintptr_t)dtb) ||
1153 ((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) > (uintptr_t)kernel_end))
Dima Zavinc46f8382013-05-03 12:23:06 -07001154 break;
1155 dtb_size = fdt_totalsize(&dtb_hdr);
1156
Lijuan Gao9f152862014-08-18 13:45:24 +08001157 dev_tree_compatible(dtb, dtb_size, dt_entry_queue);
Dima Zavinc46f8382013-05-03 12:23:06 -07001158
1159 /* goto the next device tree if any */
1160 dtb += dtb_size;
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001161 }
Dima Zavinc46f8382013-05-03 12:23:06 -07001162
Lijuan Gao9f152862014-08-18 13:45:24 +08001163 best_match_dt_entry = platform_dt_match_best(dt_entry_queue);
1164 if (best_match_dt_entry){
1165 bestmatch_tag = (void *)best_match_dt_entry->offset;
1166 bestmatch_tag_size = best_match_dt_entry->size;
1167 dprintf(INFO, "Best match DTB tags %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1168 best_match_dt_entry->platform_id, best_match_dt_entry->variant_id,
1169 best_match_dt_entry->board_hw_subtype, best_match_dt_entry->soc_rev,
1170 best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],
1171 best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],
1172 best_match_dt_entry->offset, best_match_dt_entry->size);
1173 dprintf(INFO, "Using pmic info 0x%0x/0x%x/0x%x/0x%0x for device 0x%0x/0x%x/0x%x/0x%0x\n",
1174 best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],
1175 best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],
1176 board_pmic_target(0), board_pmic_target(1),
1177 board_pmic_target(2), board_pmic_target(3));
1178 }
1179 /* free queue's memory */
1180 list_for_every_entry(&dt_entry_queue->node, dt_node_tmp1, dt_node, node) {
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001181 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001182 dt_entry_list_delete(dt_node_tmp1);
1183 dt_node_tmp1 = dt_node_tmp2;
1184 }
1185
Shashank Mittalc0f10282013-07-15 14:53:31 -07001186 if(bestmatch_tag) {
Parth Dixitc2f0cb92016-03-10 10:40:14 +05301187 if (check_aboot_addr_range_overlap((uintptr_t)tags, bestmatch_tag_size)) {
1188 dprintf(CRITICAL, "Tags addresses overlap with aboot addresses.\n");
1189 return NULL;
1190 }
Shashank Mittalc0f10282013-07-15 14:53:31 -07001191 memcpy(tags, bestmatch_tag, bestmatch_tag_size);
1192 /* clear out the old DTB magic so kernel doesn't find it */
1193 *((uint32_t *)(kernel + app_dtb_offset)) = 0;
1194 return tags;
1195 }
1196
Dima Zavinc46f8382013-05-03 12:23:06 -07001197 dprintf(CRITICAL, "DTB offset is incorrect, kernel image does not have appended DTB\n");
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001198
David Ng59c4a782015-05-14 15:51:44 -07001199 dprintf(INFO, "Device info 0x%08x/%08x/0x%08x/%u, pmic 0x%0x/0x%x/0x%x/0x%0x\n",
1200 board_platform_id(), board_soc_version(),
1201 board_target_id(), board_hardware_subtype(),
1202 board_pmic_target(0), board_pmic_target(1),
1203 board_pmic_target(2), board_pmic_target(3));
Dima Zavin77e41f32013-03-06 16:10:43 -08001204 return NULL;
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001205}
1206
Joel Kingaa335dc2013-06-03 16:11:08 -07001207/* Returns 0 if the device tree is valid. */
Deepa Dinamani87252952013-09-09 13:58:27 -07001208int dev_tree_validate(struct dt_table *table, unsigned int page_size, uint32_t *dt_hdr_size)
Joel Kingaa335dc2013-06-03 16:11:08 -07001209{
1210 int dt_entry_size;
Channagoud Kadabid87c2772014-06-20 15:41:55 -07001211 uint64_t hdr_size;
Joel Kingaa335dc2013-06-03 16:11:08 -07001212
1213 /* Validate the device tree table header */
1214 if(table->magic != DEV_TREE_MAGIC) {
1215 dprintf(CRITICAL, "ERROR: Bad magic in device tree table \n");
1216 return -1;
1217 }
1218
1219 if (table->version == DEV_TREE_VERSION_V1) {
1220 dt_entry_size = sizeof(struct dt_entry_v1);
1221 } else if (table->version == DEV_TREE_VERSION_V2) {
Lijuan Gao9f152862014-08-18 13:45:24 +08001222 dt_entry_size = sizeof(struct dt_entry_v2);
1223 } else if (table->version == DEV_TREE_VERSION_V3) {
Joel Kingaa335dc2013-06-03 16:11:08 -07001224 dt_entry_size = sizeof(struct dt_entry);
1225 } else {
1226 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
1227 table->version);
1228 return -1;
1229 }
1230
Channagoud Kadabid87c2772014-06-20 15:41:55 -07001231 hdr_size = (uint64_t)table->num_entries * dt_entry_size + DEV_TREE_HEADER_SIZE;
1232
Deepa Dinamani87252952013-09-09 13:58:27 -07001233 /* Roundup to page_size. */
1234 hdr_size = ROUNDUP(hdr_size, page_size);
1235
Channagoud Kadabid87c2772014-06-20 15:41:55 -07001236 if (hdr_size > UINT_MAX)
1237 return -1;
1238 else
1239 *dt_hdr_size = hdr_size & UINT_MAX;
Joel Kingaa335dc2013-06-03 16:11:08 -07001240
1241 return 0;
1242}
1243
Lijuan Gao9f152862014-08-18 13:45:24 +08001244static int platform_dt_absolute_match(struct dt_entry *cur_dt_entry, struct dt_entry_node *dt_list)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001245{
Lijuan Gaof8e95722014-12-23 03:03:12 -05001246 uint32_t cur_dt_hlos_ddr;
Lijuan Gao9f152862014-08-18 13:45:24 +08001247 uint32_t cur_dt_hw_platform;
1248 uint32_t cur_dt_hw_subtype;
1249 uint32_t cur_dt_msm_id;
1250 dt_node *dt_node_tmp = NULL;
Channagoud Kadabi571193a2014-02-05 13:58:49 -08001251
Lijuan Gao9f152862014-08-18 13:45:24 +08001252 /* Platform-id
1253 * bit no |31 24|23 16|15 0|
1254 * |reserved|foundry-id|msm-id|
1255 */
1256 cur_dt_msm_id = (cur_dt_entry->platform_id & 0x0000ffff);
1257 cur_dt_hw_platform = (cur_dt_entry->variant_id & 0x000000ff);
Lijuan Gao0621b862014-09-02 10:02:52 +08001258 cur_dt_hw_subtype = (cur_dt_entry->board_hw_subtype & 0xff);
Lijuan Gao9f152862014-08-18 13:45:24 +08001259
Lijuan Gaof8e95722014-12-23 03:03:12 -05001260 /* Determine the bits 10:8 to check the DT with the DDR Size */
1261 cur_dt_hlos_ddr = (cur_dt_entry->board_hw_subtype & 0x700);
Channagoud Kadabi571193a2014-02-05 13:58:49 -08001262
Lijuan Gao9f152862014-08-18 13:45:24 +08001263 /* 1. must match the msm_id, platform_hw_id, platform_subtype and DDR size
1264 * soc, board major/minor, pmic major/minor must less than board info
1265 * 2. find the matched DTB then return 1
1266 * 3. otherwise return 0
Maria Yu2e2d2c22013-07-03 19:20:33 +08001267 */
Lijuan Gao9f152862014-08-18 13:45:24 +08001268 if((cur_dt_msm_id == (board_platform_id() & 0x0000ffff)) &&
1269 (cur_dt_hw_platform == board_hardware_id()) &&
1270 (cur_dt_hw_subtype == board_hardware_subtype()) &&
Lijuan Gaof8e95722014-12-23 03:03:12 -05001271 (cur_dt_hlos_ddr == (target_get_hlos_subtype() & 0x700)) &&
Lijuan Gao9f152862014-08-18 13:45:24 +08001272 (cur_dt_entry->soc_rev <= board_soc_version()) &&
1273 ((cur_dt_entry->variant_id & 0x00ffff00) <= (board_target_id() & 0x00ffff00)) &&
1274 ((cur_dt_entry->pmic_rev[0] & 0x00ffff00) <= (board_pmic_target(0) & 0x00ffff00)) &&
1275 ((cur_dt_entry->pmic_rev[1] & 0x00ffff00) <= (board_pmic_target(1) & 0x00ffff00)) &&
1276 ((cur_dt_entry->pmic_rev[2] & 0x00ffff00) <= (board_pmic_target(2) & 0x00ffff00)) &&
1277 ((cur_dt_entry->pmic_rev[3] & 0x00ffff00) <= (board_pmic_target(3) & 0x00ffff00))) {
Maria Yu2e2d2c22013-07-03 19:20:33 +08001278
Lijuan Gao9f152862014-08-18 13:45:24 +08001279 dt_node_tmp = dt_entry_list_init();
1280 memcpy((char*)dt_node_tmp->dt_entry_m,(char*)cur_dt_entry, sizeof(struct dt_entry));
1281
1282 dprintf(SPEW, "Add DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1283 dt_node_tmp->dt_entry_m->platform_id, dt_node_tmp->dt_entry_m->variant_id,
1284 dt_node_tmp->dt_entry_m->board_hw_subtype, dt_node_tmp->dt_entry_m->soc_rev,
1285 dt_node_tmp->dt_entry_m->pmic_rev[0], dt_node_tmp->dt_entry_m->pmic_rev[1],
1286 dt_node_tmp->dt_entry_m->pmic_rev[2], dt_node_tmp->dt_entry_m->pmic_rev[3],
1287 dt_node_tmp->dt_entry_m->offset, dt_node_tmp->dt_entry_m->size);
1288
1289 insert_dt_entry_in_queue(dt_list, dt_node_tmp);
1290 return 1;
1291 }
1292 return 0;
1293}
1294
1295static int platform_dt_absolute_compat_match(struct dt_entry_node *dt_list, uint32_t dtb_info) {
1296 struct dt_entry_node *dt_node_tmp1 = NULL;
1297 struct dt_entry_node *dt_node_tmp2 = NULL;
1298 uint32_t current_info = 0;
1299 uint32_t board_info = 0;
1300 uint32_t best_info = 0;
1301 uint32_t current_pmic_model[4] = {0, 0, 0, 0};
1302 uint32_t board_pmic_model[4] = {0, 0, 0, 0};
1303 uint32_t best_pmic_model[4] = {0, 0, 0, 0};
1304 uint32_t delete_current_dt = 0;
1305 uint32_t i;
1306
1307 /* start to select the exact entry
1308 * default to exact match 0, if find current DTB entry info is the same as board info,
1309 * then exact match board info.
1310 */
1311 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1312 if (!dt_node_tmp1){
1313 dprintf(SPEW, "Current node is the end\n");
1314 break;
1315 }
1316 switch(dtb_info) {
1317 case DTB_FOUNDRY:
1318 current_info = ((dt_node_tmp1->dt_entry_m->platform_id) & 0x00ff0000);
Channagoud Kadabi4cffc272014-10-29 11:23:26 -07001319 board_info = board_foundry_id() << 16;
Lijuan Gao9f152862014-08-18 13:45:24 +08001320 break;
1321 case DTB_PMIC_MODEL:
1322 for (i = 0; i < 4; i++) {
1323 current_pmic_model[i] = (dt_node_tmp1->dt_entry_m->pmic_rev[i] & 0xff);
1324 board_pmic_model[i] = (board_pmic_target(i) & 0xff);
1325 }
1326 break;
Lijuan Gaof8e95722014-12-23 03:03:12 -05001327 case DTB_PANEL_TYPE:
1328 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0x1800);
1329 board_info = (target_get_hlos_subtype() & 0x1800);
1330 break;
1331 case DTB_BOOT_DEVICE:
1332 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0xf0000);
1333 board_info = (target_get_hlos_subtype() & 0xf0000);
1334 break;
Lijuan Gao9f152862014-08-18 13:45:24 +08001335 default:
1336 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
1337 dtb_info);
Maria Yuca51ee22013-06-27 21:45:24 +08001338 return 0;
Lijuan Gao9f152862014-08-18 13:45:24 +08001339 }
1340
1341 if (dtb_info == DTB_PMIC_MODEL) {
1342 if ((current_pmic_model[0] == board_pmic_model[0]) &&
1343 (current_pmic_model[1] == board_pmic_model[1]) &&
1344 (current_pmic_model[2] == board_pmic_model[2]) &&
1345 (current_pmic_model[3] == board_pmic_model[3])) {
1346
1347 for (i = 0; i < 4; i++) {
1348 best_pmic_model[i] = current_pmic_model[i];
1349 }
1350 break;
1351 }
1352 } else {
1353 if (current_info == board_info) {
1354 best_info = current_info;
1355 break;
1356 }
1357 }
1358 }
1359
1360 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1361 if (!dt_node_tmp1){
1362 dprintf(SPEW, "Current node is the end\n");
1363 break;
1364 }
1365 switch(dtb_info) {
1366 case DTB_FOUNDRY:
1367 current_info = ((dt_node_tmp1->dt_entry_m->platform_id) & 0x00ff0000);
1368 break;
1369 case DTB_PMIC_MODEL:
1370 for (i = 0; i < 4; i++) {
1371 current_pmic_model[i] = (dt_node_tmp1->dt_entry_m->pmic_rev[i] & 0xff);
1372 }
1373 break;
Lijuan Gaof8e95722014-12-23 03:03:12 -05001374 case DTB_PANEL_TYPE:
1375 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0x1800);
1376 break;
1377 case DTB_BOOT_DEVICE:
1378 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0xf0000);
1379 break;
Lijuan Gao9f152862014-08-18 13:45:24 +08001380 default:
1381 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
1382 dtb_info);
1383 return 0;
1384 }
1385
1386 if (dtb_info == DTB_PMIC_MODEL) {
1387 if ((current_pmic_model[0] != best_pmic_model[0]) ||
1388 (current_pmic_model[1] != best_pmic_model[1]) ||
1389 (current_pmic_model[2] != best_pmic_model[2]) ||
1390 (current_pmic_model[3] != best_pmic_model[3])) {
1391
1392 delete_current_dt = 1;
1393 }
1394 } else {
1395 if (current_info != best_info) {
1396 delete_current_dt = 1;
1397 }
1398 }
1399
1400 if (delete_current_dt) {
1401 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1402 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
1403 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
1404 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
1405 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
1406 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
1407
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001408 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001409 dt_entry_list_delete(dt_node_tmp1);
1410 dt_node_tmp1 = dt_node_tmp2;
1411 delete_current_dt = 0;
Maria Yuca51ee22013-06-27 21:45:24 +08001412 }
1413 }
Maria Yuca51ee22013-06-27 21:45:24 +08001414
Maria Yu2e2d2c22013-07-03 19:20:33 +08001415 return 1;
Maria Yuca51ee22013-06-27 21:45:24 +08001416}
1417
Lijuan Gao9f152862014-08-18 13:45:24 +08001418static int update_dtb_entry_node(struct dt_entry_node *dt_list, uint32_t dtb_info) {
1419 struct dt_entry_node *dt_node_tmp1 = NULL;
1420 struct dt_entry_node *dt_node_tmp2 = NULL;
1421 uint32_t current_info = 0;
1422 uint32_t board_info = 0;
1423 uint32_t best_info = 0;
1424
1425 /* start to select the best entry*/
1426 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1427 if (!dt_node_tmp1){
1428 dprintf(SPEW, "Current node is the end\n");
1429 break;
1430 }
1431 switch(dtb_info) {
1432 case DTB_SOC:
1433 current_info = dt_node_tmp1->dt_entry_m->soc_rev;
1434 board_info = board_soc_version();
1435 break;
1436 case DTB_MAJOR_MINOR:
1437 current_info = ((dt_node_tmp1->dt_entry_m->variant_id) & 0x00ffff00);
1438 board_info = (board_target_id() & 0x00ffff00);
1439 break;
1440 case DTB_PMIC0:
1441 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[0]) & 0x00ffff00);
1442 board_info = (board_pmic_target(0) & 0x00ffff00);
1443 break;
1444 case DTB_PMIC1:
1445 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[1]) & 0x00ffff00);
1446 board_info = (board_pmic_target(1) & 0x00ffff00);
1447 break;
1448 case DTB_PMIC2:
1449 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[2]) & 0x00ffff00);
1450 board_info = (board_pmic_target(2) & 0x00ffff00);
1451 break;
1452 case DTB_PMIC3:
1453 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[3]) & 0x00ffff00);
1454 board_info = (board_pmic_target(3) & 0x00ffff00);
1455 break;
1456 default:
1457 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
1458 dtb_info);
1459 return 0;
1460 }
1461
1462 if (current_info == board_info) {
1463 best_info = current_info;
1464 break;
1465 }
1466 if ((current_info < board_info) && (current_info > best_info)) {
1467 best_info = current_info;
1468 }
1469 if (current_info < best_info) {
1470 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1471 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
1472 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
1473 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
1474 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
1475 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
1476
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001477 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001478 dt_entry_list_delete(dt_node_tmp1);
1479 dt_node_tmp1 = dt_node_tmp2;
1480 }
1481 }
1482
1483 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1484 if (!dt_node_tmp1){
1485 dprintf(SPEW, "Current node is the end\n");
1486 break;
1487 }
1488 switch(dtb_info) {
1489 case DTB_SOC:
1490 current_info = dt_node_tmp1->dt_entry_m->soc_rev;
1491 break;
1492 case DTB_MAJOR_MINOR:
1493 current_info = ((dt_node_tmp1->dt_entry_m->variant_id) & 0x00ffff00);
1494 break;
1495 case DTB_PMIC0:
1496 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[0]) & 0x00ffff00);
1497 break;
1498 case DTB_PMIC1:
1499 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[1]) & 0x00ffff00);
1500 break;
1501 case DTB_PMIC2:
1502 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[2]) & 0x00ffff00);
1503 break;
1504 case DTB_PMIC3:
1505 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[3]) & 0x00ffff00);
1506 break;
1507 default:
1508 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
1509 dtb_info);
1510 return 0;
1511 }
1512
1513 if (current_info != best_info) {
1514 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1515 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
1516 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
1517 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
1518 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
1519 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
1520
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001521 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001522 dt_entry_list_delete(dt_node_tmp1);
1523 dt_node_tmp1 = dt_node_tmp2;
1524 }
1525 }
1526 return 1;
1527}
1528
1529static struct dt_entry *platform_dt_match_best(struct dt_entry_node *dt_list)
1530{
1531 struct dt_entry_node *dt_node_tmp1 = NULL;
1532
1533 /* check Foundry id
1534 * the foundry id must exact match board founddry id, this is compatibility check,
1535 * if couldn't find the exact match from DTB, will exact match 0x0.
1536 */
1537 if (!platform_dt_absolute_compat_match(dt_list, DTB_FOUNDRY))
1538 return NULL;
1539
1540 /* check PMIC model
1541 * the PMIC model must exact match board PMIC model, this is compatibility check,
1542 * if couldn't find the exact match from DTB, will exact match 0x0.
1543 */
1544 if (!platform_dt_absolute_compat_match(dt_list, DTB_PMIC_MODEL))
1545 return NULL;
1546
Lijuan Gaof8e95722014-12-23 03:03:12 -05001547 /* check panel type
1548 * the panel type must exact match board panel type, this is compatibility check,
1549 * if couldn't find the exact match from DTB, will exact match 0x0.
1550 */
1551 if (!platform_dt_absolute_compat_match(dt_list, DTB_PANEL_TYPE))
1552 return NULL;
1553
1554 /* check boot device subtype
1555 * the boot device subtype must exact match board boot device subtype, this is compatibility check,
1556 * if couldn't find the exact match from DTB, will exact match 0x0.
1557 */
1558 if (!platform_dt_absolute_compat_match(dt_list, DTB_BOOT_DEVICE))
1559 return NULL;
1560
Lijuan Gao9f152862014-08-18 13:45:24 +08001561 /* check soc version
1562 * the suitable soc version must less than or equal to board soc version
1563 */
1564 if (!update_dtb_entry_node(dt_list, DTB_SOC))
1565 return NULL;
1566
1567 /*check major and minor version
1568 * the suitable major&minor version must less than or equal to board major&minor version
1569 */
1570 if (!update_dtb_entry_node(dt_list, DTB_MAJOR_MINOR))
1571 return NULL;
1572
1573 /*check pmic info
1574 * the suitable pmic major&minor info must less than or equal to board pmic major&minor version
1575 */
1576 if (!update_dtb_entry_node(dt_list, DTB_PMIC0))
1577 return NULL;
1578 if (!update_dtb_entry_node(dt_list, DTB_PMIC1))
1579 return NULL;
1580 if (!update_dtb_entry_node(dt_list, DTB_PMIC2))
1581 return NULL;
1582 if (!update_dtb_entry_node(dt_list, DTB_PMIC3))
1583 return NULL;
1584
1585 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1586 if (!dt_node_tmp1) {
1587 dprintf(CRITICAL, "ERROR: Couldn't find the suitable DTB!\n");
1588 return NULL;
1589 }
1590 if (dt_node_tmp1->dt_entry_m)
1591 return dt_node_tmp1->dt_entry_m;
1592 }
1593
1594 return NULL;
1595}
1596
1597/* Function to obtain the index information for the correct device tree
1598 * based on the platform data.
1599 * If a matching device tree is found, the information is returned in the
1600 * "dt_entry_info" out parameter and a function value of 0 is returned, otherwise
1601 * a non-zero function value is returned.
1602 */
1603int dev_tree_get_entry_info(struct dt_table *table, struct dt_entry *dt_entry_info)
Maria Yuca51ee22013-06-27 21:45:24 +08001604{
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001605 uint32_t i;
Lijuan Gao9f152862014-08-18 13:45:24 +08001606 unsigned char *table_ptr = NULL;
Joel Kingaa335dc2013-06-03 16:11:08 -07001607 struct dt_entry dt_entry_buf_1;
Lijuan Gao9f152862014-08-18 13:45:24 +08001608 struct dt_entry *cur_dt_entry = NULL;
1609 struct dt_entry *best_match_dt_entry = NULL;
1610 struct dt_entry_v1 *dt_entry_v1 = NULL;
1611 struct dt_entry_v2 *dt_entry_v2 = NULL;
1612 struct dt_entry_node *dt_entry_queue = NULL;
1613 struct dt_entry_node *dt_node_tmp1 = NULL;
1614 struct dt_entry_node *dt_node_tmp2 = NULL;
Maria Yu2e2d2c22013-07-03 19:20:33 +08001615 uint32_t found = 0;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001616
Joel Kingaa335dc2013-06-03 16:11:08 -07001617 if (!dt_entry_info) {
1618 dprintf(CRITICAL, "ERROR: Bad parameter passed to %s \n",
1619 __func__);
1620 return -1;
1621 }
1622
1623 table_ptr = (unsigned char *)table + DEV_TREE_HEADER_SIZE;
1624 cur_dt_entry = &dt_entry_buf_1;
1625 best_match_dt_entry = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +08001626 dt_entry_queue = (struct dt_entry_node *)
1627 malloc(sizeof(struct dt_entry_node));
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001628
Lijuan Gao9f152862014-08-18 13:45:24 +08001629 if (!dt_entry_queue) {
1630 dprintf(CRITICAL, "Out of memory\n");
1631 return -1;
1632 }
1633
1634 list_initialize(&dt_entry_queue->node);
1635 dprintf(INFO, "DTB Total entry: %d, DTB version: %d\n", table->num_entries, table->version);
Maria Yu2e2d2c22013-07-03 19:20:33 +08001636 for(i = 0; found == 0 && i < table->num_entries; i++)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001637 {
Joel Kingaa335dc2013-06-03 16:11:08 -07001638 memset(cur_dt_entry, 0, sizeof(struct dt_entry));
1639 switch(table->version) {
1640 case DEV_TREE_VERSION_V1:
1641 dt_entry_v1 = (struct dt_entry_v1 *)table_ptr;
1642 cur_dt_entry->platform_id = dt_entry_v1->platform_id;
1643 cur_dt_entry->variant_id = dt_entry_v1->variant_id;
1644 cur_dt_entry->soc_rev = dt_entry_v1->soc_rev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001645 cur_dt_entry->board_hw_subtype = (dt_entry_v1->variant_id >> 0x18);
1646 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
1647 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
1648 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
1649 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
Joel Kingaa335dc2013-06-03 16:11:08 -07001650 cur_dt_entry->offset = dt_entry_v1->offset;
1651 cur_dt_entry->size = dt_entry_v1->size;
1652 table_ptr += sizeof(struct dt_entry_v1);
1653 break;
1654 case DEV_TREE_VERSION_V2:
Lijuan Gao9f152862014-08-18 13:45:24 +08001655 dt_entry_v2 = (struct dt_entry_v2*)table_ptr;
1656 cur_dt_entry->platform_id = dt_entry_v2->platform_id;
1657 cur_dt_entry->variant_id = dt_entry_v2->variant_id;
1658 cur_dt_entry->soc_rev = dt_entry_v2->soc_rev;
1659 /* For V2 version of DTBs we have platform version field as part
1660 * of variant ID, in such case the subtype will be mentioned as 0x0
1661 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
1662 * SS -- Subtype
1663 * PM -- Platform major version
1664 * Pm -- Platform minor version
1665 * PH -- Platform hardware CDP/MTP
1666 * In such case to make it compatible with LK algorithm move the subtype
1667 * from variant_id to subtype field
1668 */
1669 if (dt_entry_v2->board_hw_subtype == 0)
1670 cur_dt_entry->board_hw_subtype = (cur_dt_entry->variant_id >> 0x18);
1671 else
1672 cur_dt_entry->board_hw_subtype = dt_entry_v2->board_hw_subtype;
1673 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
1674 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
1675 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
1676 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
1677 cur_dt_entry->offset = dt_entry_v2->offset;
1678 cur_dt_entry->size = dt_entry_v2->size;
1679 table_ptr += sizeof(struct dt_entry_v2);
1680 break;
1681 case DEV_TREE_VERSION_V3:
Joel Kingaa335dc2013-06-03 16:11:08 -07001682 memcpy(cur_dt_entry, (struct dt_entry *)table_ptr,
1683 sizeof(struct dt_entry));
Lijuan Gao9f152862014-08-18 13:45:24 +08001684 /* For V3 version of DTBs we have platform version field as part
1685 * of variant ID, in such case the subtype will be mentioned as 0x0
1686 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
1687 * SS -- Subtype
1688 * PM -- Platform major version
1689 * Pm -- Platform minor version
1690 * PH -- Platform hardware CDP/MTP
1691 * In such case to make it compatible with LK algorithm move the subtype
1692 * from variant_id to subtype field
1693 */
1694 if (cur_dt_entry->board_hw_subtype == 0)
1695 cur_dt_entry->board_hw_subtype = (cur_dt_entry->variant_id >> 0x18);
1696
Joel Kingaa335dc2013-06-03 16:11:08 -07001697 table_ptr += sizeof(struct dt_entry);
1698 break;
1699 default:
1700 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
1701 table->version);
Lijuan Gao9f152862014-08-18 13:45:24 +08001702 free(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001703 return -1;
1704 }
1705
Lijuan Gao9f152862014-08-18 13:45:24 +08001706 /* DTBs must match the platform_id, platform_hw_id, platform_subtype and DDR size.
1707 * The satisfactory DTBs are stored in dt_entry_queue
1708 */
1709 platform_dt_absolute_match(cur_dt_entry, dt_entry_queue);
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -08001710
Lijuan Gao9f152862014-08-18 13:45:24 +08001711 }
1712 best_match_dt_entry = platform_dt_match_best(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001713 if (best_match_dt_entry) {
1714 *dt_entry_info = *best_match_dt_entry;
Maria Yu2e2d2c22013-07-03 19:20:33 +08001715 found = 1;
1716 }
1717
1718 if (found != 0) {
Sundarajan Srinivasan763c0db2014-05-20 17:08:36 -07001719 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 -07001720 dt_entry_info->platform_id, dt_entry_info->soc_rev,
1721 dt_entry_info->variant_id, dt_entry_info->board_hw_subtype,
Lijuan Gao9f152862014-08-18 13:45:24 +08001722 board_platform_id(), board_soc_version(),
1723 board_target_id(), board_hardware_subtype());
1724 if (dt_entry_info->pmic_rev[0] == 0 && dt_entry_info->pmic_rev[0] == 0 &&
1725 dt_entry_info->pmic_rev[0] == 0 && dt_entry_info->pmic_rev[0] == 0) {
1726 dprintf(SPEW, "No maintain pmic info in DTB, device pmic info is 0x%0x/0x%x/0x%x/0x%0x\n",
1727 board_pmic_target(0), board_pmic_target(1),
1728 board_pmic_target(2), board_pmic_target(3));
1729 } else {
1730 dprintf(INFO, "Using pmic info 0x%0x/0x%x/0x%x/0x%0x for device 0x%0x/0x%x/0x%x/0x%0x\n",
1731 dt_entry_info->pmic_rev[0], dt_entry_info->pmic_rev[1],
1732 dt_entry_info->pmic_rev[2], dt_entry_info->pmic_rev[3],
1733 board_pmic_target(0), board_pmic_target(1),
1734 board_pmic_target(2), board_pmic_target(3));
1735 }
Joel Kingaa335dc2013-06-03 16:11:08 -07001736 return 0;
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -08001737 }
1738
Lijuan Gao9f152862014-08-18 13:45:24 +08001739 dprintf(CRITICAL, "ERROR: Unable to find suitable device tree for device (%u/0x%08x/0x%08x/%u)\n",
1740 board_platform_id(), board_soc_version(),
1741 board_target_id(), board_hardware_subtype());
1742
1743 list_for_every_entry(&dt_entry_queue->node, dt_node_tmp1, dt_node, node) {
1744 /* free node memory */
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001745 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001746 dt_entry_list_delete(dt_node_tmp1);
1747 dt_node_tmp1 = dt_node_tmp2;
1748 }
1749 free(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001750 return -1;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001751}
1752
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001753/* Function to add the first RAM partition info to the device tree.
1754 * Note: The function replaces the reg property in the "/memory" node
1755 * with the addr and size provided.
1756 */
1757int dev_tree_add_first_mem_info(uint32_t *fdt, uint32_t offset, uint32_t addr, uint32_t size)
1758{
1759 int ret;
1760
1761 ret = fdt_setprop_u32(fdt, offset, "reg", addr);
1762
1763 if (ret)
1764 {
1765 dprintf(CRITICAL, "Failed to add the memory information addr: %d\n",
1766 ret);
1767 }
1768
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001769 ret = fdt_appendprop_u32(fdt, offset, "reg", size);
1770
1771 if (ret)
1772 {
1773 dprintf(CRITICAL, "Failed to add the memory information size: %d\n",
1774 ret);
1775 }
1776
1777 return ret;
1778}
1779
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001780static 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 -07001781{
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001782 int len;
1783 uint32_t *valp;
1784 int ret;
1785 uint32_t offset;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001786
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001787 mem_node->offset = mem_node_offset;
1788
1789 /* Get offset of the root node */
1790 ret = fdt_path_offset(fdt, "/");
1791 if (ret < 0)
1792 {
1793 dprintf(CRITICAL, "Could not find memory node.\n");
1794 return ret;
1795 }
1796
1797 offset = ret;
1798
1799 /* Find the #address-cells size. */
1800 valp = (uint32_t*)fdt_getprop(fdt, offset, "#address-cells", &len);
Lijuan Gaoae0927b2014-07-18 17:16:16 +08001801 if (len <= 0 || !valp)
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001802 {
1803 if (len == -FDT_ERR_NOTFOUND)
1804 {
1805 /* Property not found.
1806 * Assume standard sizes.
1807 */
1808 mem_node->addr_cell_size = 2;
1809 dprintf(CRITICAL, "Using default #addr_cell_size: %u\n", mem_node->addr_cell_size);
1810 }
1811 else
1812 {
1813 dprintf(CRITICAL, "Error finding the #address-cells property\n");
1814 return len;
1815 }
1816 }
1817 else
1818 mem_node->addr_cell_size = fdt32_to_cpu(*valp);
1819
1820 /* Find the #size-cells size. */
1821 valp = (uint32_t*)fdt_getprop(fdt, offset, "#size-cells", &len);
Lijuan Gaoae0927b2014-07-18 17:16:16 +08001822 if (len <= 0 || !valp)
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001823 {
1824 if (len == -FDT_ERR_NOTFOUND)
1825 {
1826 /* Property not found.
1827 * Assume standard sizes.
1828 */
1829 mem_node->size_cell_size = 1;
1830 dprintf(CRITICAL, "Using default #size_cell_size: %u\n", mem_node->size_cell_size);
1831 }
1832 else
1833 {
1834 dprintf(CRITICAL, "Error finding the #size-cells property\n");
1835 return len;
1836 }
1837 }
1838 else
1839 mem_node->size_cell_size = fdt32_to_cpu(*valp);
1840
1841 return 0;
1842}
1843
1844static void dev_tree_update_memory_node(uint32_t offset)
1845{
1846 mem_node.offset = offset;
1847 mem_node.addr_cell_size = 1;
1848 mem_node.size_cell_size = 1;
1849}
1850
1851/* Function to add the subsequent RAM partition info to the device tree. */
1852int dev_tree_add_mem_info(void *fdt, uint32_t offset, uint64_t addr, uint64_t size)
1853{
1854 int ret = 0;
1855
1856 if(smem_get_ram_ptable_version() >= 1)
1857 {
1858 ret = dev_tree_query_memory_cell_sizes(fdt, &mem_node, offset);
1859 if (ret < 0)
1860 {
1861 dprintf(CRITICAL, "Could not find #address-cells and #size-cells properties: ret %d\n", ret);
1862 return ret;
1863 }
1864
1865 }
1866 else
1867 {
1868 dev_tree_update_memory_node(offset);
1869 }
1870
1871 if (!(mem_node.mem_info_cnt))
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001872 {
1873 /* Replace any other reg prop in the memory node. */
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001874
1875 /* cell_size is the number of 32 bit words used to represent an address/length in the device tree.
1876 * memory node in DT can be either 32-bit(cell-size = 1) or 64-bit(cell-size = 2).So when updating
1877 * the memory node in the device tree, we write one word or two words based on cell_size = 1 or 2.
1878 */
1879
1880 if(mem_node.addr_cell_size == 2)
1881 {
1882 ret = fdt_setprop_u32(fdt, mem_node.offset, "reg", addr >> 32);
1883 if(ret)
1884 {
1885 dprintf(CRITICAL, "ERROR: Could not set prop reg for memory node\n");
1886 return ret;
1887 }
1888
1889 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1890 if(ret)
1891 {
1892 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1893 return ret;
1894 }
1895 }
1896 else
1897 {
1898 ret = fdt_setprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1899 if(ret)
1900 {
1901 dprintf(CRITICAL, "ERROR: Could not set prop reg for memory node\n");
1902 return ret;
1903 }
1904 }
1905
1906 mem_node.mem_info_cnt = 1;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001907 }
1908 else
1909 {
1910 /* Append the mem info to the reg prop for subsequent nodes. */
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001911 if(mem_node.addr_cell_size == 2)
1912 {
1913 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", addr >> 32);
1914 if(ret)
1915 {
1916 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1917 return ret;
1918 }
1919 }
1920
1921 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1922 if(ret)
1923 {
1924 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1925 return ret;
1926 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001927 }
1928
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001929 if(mem_node.size_cell_size == 2)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001930 {
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001931 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", size>>32);
1932 if(ret)
1933 {
1934 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1935 return ret;
1936 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001937 }
1938
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001939 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)size);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001940
1941 if (ret)
1942 {
1943 dprintf(CRITICAL, "Failed to add the memory information size: %d\n",
1944 ret);
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001945 return ret;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001946 }
1947
1948 return ret;
1949}
1950
1951/* Top level function that updates the device tree. */
1952int update_device_tree(void *fdt, const char *cmdline,
1953 void *ramdisk, uint32_t ramdisk_size)
1954{
1955 int ret = 0;
1956 uint32_t offset;
lijuangc76a7632017-12-07 14:37:56 +08001957#if ENABLE_KASLRSEED_SUPPORT
1958 uintptr_t kaslrseed;
1959#endif
Mayank Grover2533aab2018-02-23 18:06:07 +05301960 uint32_t cmdline_len = 0;
1961
1962 if (cmdline)
1963 cmdline_len = strlen(cmdline);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001964
1965 /* Check the device tree header */
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +05301966 ret = fdt_check_header(fdt) || fdt_check_header_ext(fdt);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001967 if (ret)
1968 {
1969 dprintf(CRITICAL, "Invalid device tree header \n");
1970 return ret;
1971 }
1972
P.V. Phani Kumar9cd95102016-03-09 12:35:23 +05301973 if (check_aboot_addr_range_overlap((uint32_t)fdt,
Mayank Grover2533aab2018-02-23 18:06:07 +05301974 (fdt_totalsize(fdt) + DTB_PAD_SIZE + cmdline_len))) {
P.V. Phani Kumar9cd95102016-03-09 12:35:23 +05301975 dprintf(CRITICAL, "Error: Fdt addresses overlap with aboot addresses.\n");
1976 return ret;
1977 }
1978
Deepa Dinamani1c970732013-04-19 14:23:01 -07001979 /* Add padding to make space for new nodes and properties. */
Mayank Grover2533aab2018-02-23 18:06:07 +05301980 ret = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + DTB_PAD_SIZE + cmdline_len);
Deepa Dinamani1c970732013-04-19 14:23:01 -07001981 if (ret!= 0)
1982 {
1983 dprintf(CRITICAL, "Failed to move/resize dtb buffer: %d\n", ret);
1984 return ret;
1985 }
1986
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001987 /* Get offset of the memory node */
1988 ret = fdt_path_offset(fdt, "/memory");
1989 if (ret < 0)
1990 {
1991 dprintf(CRITICAL, "Could not find memory node.\n");
1992 return ret;
1993 }
1994
1995 offset = ret;
1996
1997 ret = target_dev_tree_mem(fdt, offset);
1998 if(ret)
1999 {
2000 dprintf(CRITICAL, "ERROR: Cannot update memory node\n");
2001 return ret;
2002 }
2003
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002004 /* Get offset of the chosen node */
2005 ret = fdt_path_offset(fdt, "/chosen");
2006 if (ret < 0)
2007 {
2008 dprintf(CRITICAL, "Could not find chosen node.\n");
2009 return ret;
2010 }
2011
2012 offset = ret;
Maria Yuabde9542014-07-07 14:49:34 +08002013 if (cmdline)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002014 {
Maria Yuabde9542014-07-07 14:49:34 +08002015 /* Adding the cmdline to the chosen node */
2016 ret = fdt_appendprop_string(fdt, offset, (const char*)"bootargs", (const void*)cmdline);
2017 if (ret)
2018 {
2019 dprintf(CRITICAL, "ERROR: Cannot update chosen node [bootargs]\n");
2020 return ret;
2021 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002022 }
2023
lijuangc76a7632017-12-07 14:37:56 +08002024#if ENABLE_KASLRSEED_SUPPORT
2025 if (!scm_random(&kaslrseed, sizeof(kaslrseed))) {
2026 /* Adding Kaslr Seed to the chosen node */
2027 ret = fdt_appendprop_u64 (fdt, offset, (const char *)"kaslr-seed", (uint64_t)kaslrseed);
2028 if (ret)
2029 dprintf(CRITICAL, "ERROR: Cannot update chosen node [kaslr-seed] - 0x%x\n", ret);
2030 else
2031 dprintf(CRITICAL, "kaslr-Seed is added to chosen node\n");
2032 } else {
2033 dprintf(CRITICAL, "ERROR: Cannot generate Kaslr Seed\n");
2034 }
2035#endif
2036
Joonwoo Parka5b5f492014-02-13 18:24:48 -08002037 if (ramdisk_size) {
2038 /* Adding the initrd-start to the chosen node */
2039 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-start",
2040 (uint32_t)ramdisk);
2041 if (ret)
2042 {
2043 dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-start]\n");
2044 return ret;
2045 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002046
Joonwoo Parka5b5f492014-02-13 18:24:48 -08002047 /* Adding the initrd-end to the chosen node */
2048 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-end",
2049 ((uint32_t)ramdisk + ramdisk_size));
2050 if (ret)
2051 {
2052 dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-end]\n");
2053 return ret;
2054 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002055 }
2056
Kishor PK536904a2017-07-13 17:18:59 +05302057#if ENABLE_BOOTDEVICE_MOUNT
2058 /* Update fstab node */
2059 dprintf(SPEW, "Start of fstab node update:%zu ms\n", platform_get_sclk_count());
2060 if (update_fstab_node(fdt) != 0) {
2061 dprintf(CRITICAL, "ERROR: Cannot update fstab node\n");
2062 return ret;
2063 }
2064 dprintf(SPEW, "End of fstab node update:%zu ms\n", platform_get_sclk_count());
2065#endif
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002066 fdt_pack(fdt);
2067
Channagoud Kadabiffaea422014-12-05 15:45:41 -08002068#if ENABLE_PARTIAL_GOODS_SUPPORT
2069 update_partial_goods_dtb_nodes(fdt);
2070#endif
2071
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002072 return ret;
2073}
Kishor PK536904a2017-07-13 17:18:59 +05302074
2075#if ENABLE_BOOTDEVICE_MOUNT
2076/*Update device tree for fstab node */
2077static int update_fstab_node(void *fdt)
2078{
2079 int ret = 0;
2080 int str_len = 0;
2081 int parent_offset = 0;
2082 int subnode_offset = 0;
2083 int prop_length = 0;
2084 int prefix_string_len = 0;
2085 char *node_name = NULL;
2086 char *boot_dev_buf = NULL;
2087 char *new_str = NULL;
2088 char *prefix_str = NULL;
2089 char *suffix_str = NULL;
2090 const struct fdt_property *prop = NULL;
2091
2092 /* Find the parent node */
2093 parent_offset = fdt_path_offset(fdt, fstab_table.parent_node);
2094 if (parent_offset < 0) {
2095 dprintf(CRITICAL, "Failed to get parent node: fstab error: %d\n", parent_offset);
2096 return -1;
2097 }
2098 dprintf(SPEW, "Node: %s found.\n", fdt_get_name(fdt, parent_offset, NULL));
2099
2100 /* Get boot device type */
2101 boot_dev_buf = (char *) malloc(sizeof(char) * BOOT_DEV_MAX_LEN);
2102 if (!boot_dev_buf) {
2103 dprintf(CRITICAL, "Failed to allocate memory for boot device\n");
2104 return -1;
2105 }
2106
2107 new_str = (char *) malloc(sizeof(char) * NODE_PROPERTY_MAX_LEN);
2108 if (!new_str) {
2109 dprintf(CRITICAL, "Failed to allocate memory for node property string\n");
2110 return -1;
2111 }
2112
2113
2114 platform_boot_dev_cmdline(boot_dev_buf);
2115
2116 /* Get properties of all sub nodes */
2117 for (subnode_offset = fdt_first_subnode(fdt, parent_offset); subnode_offset >= 0; subnode_offset = fdt_next_subnode(fdt, subnode_offset)) {
2118 prop = fdt_get_property(fdt, subnode_offset, fstab_table.node_prop, &prop_length);
2119 node_name = (char *)(uintptr_t)fdt_get_name(fdt, subnode_offset, NULL);
2120 if (!prop) {
2121 dprintf(CRITICAL, "Property:%s is not found for sub node:%s\n", fstab_table.node_prop, node_name);
2122 } else {
2123 dprintf(CRITICAL, "Property:%s found for sub node:%s\tproperty:%s\n", fstab_table.node_prop, node_name, prop->data);
2124 /* Pointer to fdt 'dev' property string that needs to update based on the 'androidboot.bootdevice' */
2125 memset(new_str, 0, NODE_PROPERTY_MAX_LEN);
2126 prefix_str = (char *)prop->data;
2127 if (strlen(prefix_str) > NODE_PROPERTY_MAX_LEN) {
2128 dprintf(CRITICAL, "Property string length is greater than node property max length\n");
2129 continue;
2130 }
2131 suffix_str = strstr(prefix_str, fstab_table.device_path_id);
2132 if (!suffix_str) {
2133 dprintf(CRITICAL, "Property is not proper to update\n");
2134 continue;
2135 }
2136 suffix_str += strlen(fstab_table.device_path_id);
2137 prefix_string_len = strlen(prefix_str) - (strlen(suffix_str) - 1);
2138 suffix_str = strstr((suffix_str + 1), "/");
2139 str_len = strlcpy(new_str, prefix_str, prefix_string_len);
2140 if (!str_len) {
2141 dprintf(CRITICAL, "Property length is not proper to update\n");
2142 continue;
2143 }
2144 str_len = strlcat(new_str, boot_dev_buf, strlen(prefix_str));
2145 if (!str_len) {
2146 dprintf(CRITICAL, "Property length is not proper to update\n");
2147 continue;
2148 }
2149 str_len = strlcat(new_str, suffix_str, strlen(prefix_str));
2150 if (!str_len) {
2151 dprintf(CRITICAL, "Property length is not proper to update\n");
2152 continue;
2153 }
2154 /* Update the new property in the memory */
2155 memscpy(prefix_str, strlen(prefix_str), new_str, strlen(new_str) + 1);
2156 /* Update the property with new value */
2157 ret = fdt_setprop(fdt, subnode_offset, fstab_table.node_prop, (const void *)prefix_str, strlen(prefix_str) + 1);
2158 if(ret) {
2159 dprintf(CRITICAL, "Failed to update the node with new property\n");
2160 continue;
2161 }
2162 dprintf(CRITICAL, "Updated %s with new property %s\n", node_name, prop->data);
2163 }
2164 }
2165 if (boot_dev_buf)
2166 free(boot_dev_buf);
2167 if (new_str)
2168 free(new_str);
2169 return ret;
2170}
2171#endif