blob: 6a99514caf5fb421d089c9499486be6753769ab7 [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
Mayank Grover1b6da5d2017-12-19 16:05:46 +053066dtbo_error ret = DTBO_SUCCESS;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -070067
Joel Kingaa335dc2013-06-03 16:11:08 -070068struct dt_entry_v1
69{
70 uint32_t platform_id;
71 uint32_t variant_id;
72 uint32_t soc_rev;
73 uint32_t offset;
74 uint32_t size;
75};
76
Kishor PK536904a2017-07-13 17:18:59 +053077#if ENABLE_BOOTDEVICE_MOUNT
78/* Look up table for fstab node */
79struct fstab_node
80{
81 const char *parent_node;
82 const char *node_prop;
83 const char *device_path_id;
84};
85
86static struct fstab_node fstab_table =
87{
88 "/firmware/android/fstab", "dev", "/soc/"
89};
90#endif
91
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -070092static struct dt_mem_node_info mem_node;
Lijuan Gao9f152862014-08-18 13:45:24 +080093static int platform_dt_absolute_match(struct dt_entry *cur_dt_entry, struct dt_entry_node *dt_list);
94static struct dt_entry *platform_dt_match_best(struct dt_entry_node *dt_list);
95static int update_dtb_entry_node(struct dt_entry_node *dt_list, uint32_t dtb_info);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -070096extern int target_is_emmc_boot(void);
97extern uint32_t target_dev_tree_mem(void *fdt, uint32_t memory_node_offset);
Kishor PK536904a2017-07-13 17:18:59 +053098static int update_fstab_node(void *fdt);
99
Deepa Dinamanic55f01b2013-05-30 14:05:56 -0700100/* TODO: This function needs to be moved to target layer to check violations
101 * against all the other regions as well.
102 */
Vijay Kumar Pendoti9c002ad2016-03-09 13:52:45 +0530103extern int check_aboot_addr_range_overlap(uintptr_t start, uint32_t size);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700104
lijuang0cce8bf2018-08-23 10:56:42 +0800105static int dtbo_idx = INVALID_PTN;
106int get_dtbo_idx (void)
107{
108 return dtbo_idx;
109}
110
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +0530111int fdt_check_header_ext(const void *fdt)
112{
113 uintptr_t fdt_start, fdt_end;
114 fdt_start = (uintptr_t)fdt;
115 if(fdt_start + fdt_totalsize(fdt) < fdt_start)
116 {
117 dprintf(CRITICAL,"Integer over in fdt header %s\t%d",__func__,__LINE__);
118 return FDT_ERR_BADOFFSET;
119 }
120 fdt_end = fdt_start + fdt_totalsize(fdt);
121
122 if (((uint64_t)fdt_start + (uint64_t)fdt_off_dt_struct(fdt) + (uint64_t)fdt_size_dt_struct(fdt)) > UINT_MAX)
123 return FDT_ERR_BADOFFSET;
124
125 if ((fdt_start + fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt)) > fdt_end)
126 return FDT_ERR_BADOFFSET;
127
128 if (((uint64_t)fdt_start + (uint64_t)fdt_off_dt_strings(fdt) + (uint64_t)fdt_size_dt_strings(fdt)) > UINT_MAX)
129 return FDT_ERR_BADOFFSET;
130
131 if ((fdt_start + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)) > fdt_end)
132 return FDT_ERR_BADOFFSET;
133
134 return 0;
135}
136
Shashank Mittalc0f10282013-07-15 14:53:31 -0700137/* Returns soc version if platform id and hardware id matches
138 otherwise return 0xFFFFFFFF */
139#define INVALID_SOC_REV_ID 0XFFFFFFFF
Lijuan Gao9f152862014-08-18 13:45:24 +0800140
141/* Add function to allocate dt entry list, used for recording
142* the entry which conform to platform_dt_absolute_match()
143*/
144static struct dt_entry_node *dt_entry_list_init(void)
145{
146 struct dt_entry_node *dt_node_member = NULL;
147
148 dt_node_member = (struct dt_entry_node *)
149 malloc(sizeof(struct dt_entry_node));
150
151 ASSERT(dt_node_member);
152
153 list_clear_node(&dt_node_member->node);
154 dt_node_member->dt_entry_m = (struct dt_entry *)
155 malloc(sizeof(struct dt_entry));
156 ASSERT(dt_node_member->dt_entry_m);
157
158 memset(dt_node_member->dt_entry_m ,0 ,sizeof(struct dt_entry));
159 return dt_node_member;
160}
161
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530162/*
163 * Function to validate dtbo image.
164 * return: TRUE or FALSE.
165 */
Mayank Groverb61c0c22018-09-04 15:09:32 +0530166dtbo_error load_validate_dtbo_image(void **dtbo_buf, uint32_t *dtbo_image_sz)
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530167{
168 uint64_t dtbo_total_size = 0;
Mayank Groverb61c0c22018-09-04 15:09:32 +0530169 static void *dtbo_image_buf = NULL;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530170 unsigned int dtbo_image_buf_size;
171 unsigned int dtbo_partition_size;
Mayank Groverb61c0c22018-09-04 15:09:32 +0530172 unsigned long long ptn, boot_img_sz;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530173 int index = INVALID_PTN;
174 int page_size = mmc_page_size();
175 struct dtbo_table_hdr *dtbo_table_header = NULL;
176 dtbo_error ret = DTBO_SUCCESS;
Mayank Groverb61c0c22018-09-04 15:09:32 +0530177 static bool dtbo_loaded = false;
178 static unsigned long long ptn_size = 0;
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530179 uint32_t recovery_dtbo_size = 0;
180 void *recovery_appended_dtbo = NULL;
Mayank Groverb61c0c22018-09-04 15:09:32 +0530181
182 /* If dtbo loaded skip loading */
183 if (dtbo_loaded)
184 goto out;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530185
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530186 get_recovery_dtbo_info(&recovery_dtbo_size, &recovery_appended_dtbo);
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530187
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530188 /* Intialize dtbo for recovery header v1 */
189 if (recovery_dtbo_size && recovery_appended_dtbo) {
190 dtbo_image_buf = recovery_appended_dtbo;
191 dtbo_partition_size = recovery_dtbo_size;
192 ptn_size = recovery_dtbo_size;
193 } else {
194 index = partition_get_index("dtbo");
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530195
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530196
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530197 /* Immediately return if dtbo is not supported */
198 if (index == INVALID_PTN)
199 {
200 ret = DTBO_NOT_SUPPORTED;
201 goto out;
202 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530203
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530204 ptn = partition_get_offset(index);
205 if(!ptn)
206 {
207 dprintf(CRITICAL, "ERROR: dtbo parition failed to get offset. \n");
208 ret = DTBO_ERROR;
209 goto out;
210 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530211
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530212 ptn_size = partition_get_size(index);
213 if (ptn_size > MAX_SUPPORTED_DTBO_IMG_BUF)
214 {
215 dprintf(CRITICAL, "ERROR: dtbo parition size is greater than supported.\n");
216 ret = DTBO_ERROR;
217 goto out;
218 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530219
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530220 /*
221 Read dtbo image into scratch region after kernel image.
222 dtbo_image_buf_size = total_scratch_region_size - boot_img_sz
223 */
224 boot_img_sz = partition_get_size(partition_get_index("boot"));
225 if (!boot_img_sz)
226 {
227 dprintf(CRITICAL, "ERROR: Unable to get boot partition size\n");
228 ret = DTBO_NOT_SUPPORTED;
229 goto out;
230 }
231
232 dtbo_image_buf_size = target_get_max_flash_size() - boot_img_sz;
233 dtbo_partition_size = ptn_size + ADDR_ALIGNMENT;
234 dtbo_partition_size = ROUND_TO_PAGE(dtbo_partition_size, (page_size - 1)); /* Maximum dtbo size possible */
235 if (dtbo_partition_size == UINT_MAX ||
236 dtbo_image_buf_size < dtbo_partition_size)
237 {
238 dprintf(CRITICAL, "ERROR: Invalid DTBO partition size\n");
239 ret = DTBO_NOT_SUPPORTED;
240 goto out;
241 }
242
243 mmc_set_lun(partition_get_lun(index));
244 /* read dtbo at last 10MB of scratch */
245 dtbo_image_buf = target_get_scratch_address() +
246 (target_get_max_flash_size() - DTBO_IMG_BUF);
247 dtbo_image_buf =
248 (void *)ROUND_TO_PAGE((addr_t)dtbo_image_buf, (ADDR_ALIGNMENT-1) );
249 if(dtbo_image_buf == (void *)UINT_MAX)
250 {
251 dprintf(CRITICAL, "ERROR: Invalid DTBO image buf addr\n");
252 ret = DTBO_NOT_SUPPORTED;
253 goto out;
254 }
255
256 /* Read dtbo partition with header */
257 if (mmc_read(ptn, (uint32_t *)(dtbo_image_buf), dtbo_partition_size))
258 {
259 dprintf(CRITICAL, "ERROR: dtbo partition mmc read failure \n");
260 ret = DTBO_ERROR;
261 goto out;
262 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530263 }
264
265 /* validate the dtbo image, before reading complete image */
266 dtbo_table_header = (struct dtbo_table_hdr *)dtbo_image_buf;
267
268 /*Check for dtbo magic*/
269 if (fdt32_to_cpu(dtbo_table_header->magic) != DTBO_TABLE_MAGIC)
270 {
271 dprintf(CRITICAL, "dtbo header magic mismatch %x, with %x\n",
272 fdt32_to_cpu(dtbo_table_header->magic), DTBO_TABLE_MAGIC);
273 ret = DTBO_ERROR;
274 goto out;
275 }
276
277 /*Check for dtbo image table size*/
278 if (fdt32_to_cpu(dtbo_table_header->hdr_size) != sizeof(struct dtbo_table_hdr))
279 {
280 dprintf(CRITICAL, "dtbo table header size got corrupted\n");
281 ret = DTBO_ERROR;
282 goto out;
283 }
284
285 /*Check for dt entry size of dtbo image*/
286 if (fdt32_to_cpu(dtbo_table_header->dt_entry_size) != sizeof(struct dtbo_table_entry))
287 {
288 dprintf(CRITICAL, "dtbo table dt entry size got corrupted\n");
289 ret = DTBO_ERROR;
290 goto out;
291 }
292
293 /*Total size of dtbo */
294 dtbo_total_size = fdt32_to_cpu(dtbo_table_header->total_size);
295 if (dtbo_total_size > dtbo_partition_size || dtbo_total_size == 0)
296 {
297 dprintf(CRITICAL, "dtbo table total size exceeded the dtbo buffer allocated\n");
298 ret = DTBO_ERROR;
299 goto out;
300 }
301
302 /* Total size of dtbo entries */
303 dtbo_total_size = fdt32_to_cpu(dtbo_table_header->dt_entry_count) *
304 fdt32_to_cpu(dtbo_table_header->dt_entry_size);
305 if (dtbo_total_size > dtbo_partition_size || dtbo_total_size == 0)
306 {
307 dprintf(CRITICAL, "dtbo table total size exceeded the dtbo buffer allocated\n");
308 ret = DTBO_ERROR;
309 goto out;
310 }
311
312 /* Offset should be less than image size */
313 if (fdt32_to_cpu(dtbo_table_header->dt_entry_offset) > dtbo_partition_size)
314 {
315 dprintf(CRITICAL, "dtbo offset exceeds the dtbo buffer allocated\n");
316 ret = DTBO_ERROR;
317 goto out;
318 }
319
320 /* Offset + total size is less than image size */
321 if (dtbo_total_size + fdt32_to_cpu(dtbo_table_header->dt_entry_offset) > dtbo_partition_size)
322 {
323 dprintf(CRITICAL, "dtbo size exceeded the dtbo buffer allocated\n");
324 ret = DTBO_ERROR;
325 }
326
327out:
Mayank Groverb61c0c22018-09-04 15:09:32 +0530328 if (ret == DTBO_SUCCESS)
329 {
330 *dtbo_buf = dtbo_image_buf;
331 *dtbo_image_sz = (uint32_t)ptn_size;
332 dtbo_loaded = true;
333 }
334 else
335 {
336 *dtbo_buf = NULL;
337 *dtbo_image_sz = 0;
338 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530339 return ret;
340}
341
342static bool check_all_bits_set(uint32_t matchdt_value)
343{
344 return (matchdt_value & ALL_BITS_SET) == (ALL_BITS_SET);
345}
346
347/* Dt selection table for quick reference
348 | SNO | Dt Property | CDT Property | Exact | Best | Default |
349 |-----+---------------+-----------------+-------+------+---------+
350 | | qcom, msm-id | | | | |
351 | | | PlatformId | Y | N | N |
352 | | | SocRev | N | Y | N |
353 | | | FoundryId | Y | N | 0 |
354 | | qcom,board-id | | | | |
355 | | | VariantId | Y | N | N |
356 | | | VariantMajor | N | Y | N |
357 | | | VariantMinor | N | Y | N |
358 | | | PlatformSubtype | Y | N | 0 |
359 | | qcom,pmic-id | | | | |
360 | | | PmicModelId | Y | N | 0 |
361 | | | PmicMetalRev | N | Y | N |
362 | | | PmicLayerRev | N | Y | N |
363 | | | PmicVariantRev | N | Y | N |
364*/
365
lijuang0cce8bf2018-08-23 10:56:42 +0800366static boolean dtb_read_find_match(dt_info *current_dtb_info, dt_info *best_dtb_info, uint32_t exact_match)
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530367{
368 int board_id_len;
369 int platform_id_len = 0;
370 int pmic_id_len;
371 int root_offset = 0;
372 void *dtb = current_dtb_info->dtb;
373 uint32_t idx;
374 const char *platform_prop = NULL;
375 const char *board_prop = NULL;
376 const char *pmic_prop = NULL;
lijuang0cce8bf2018-08-23 10:56:42 +0800377 boolean find_best_match = false;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530378
379 current_dtb_info->dt_match_val = 0;
380 root_offset = fdt_path_offset(dtb, "/");
381 if (root_offset < 0) {
382 dprintf(CRITICAL, "ERROR: Unable to locate root node\n");
lijuang0cce8bf2018-08-23 10:56:42 +0800383 return false;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530384 }
385
386 /* Get the msm-id prop from DTB and find best match */
387 platform_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,msm-id", &platform_id_len);
388 if (platform_prop && (platform_id_len > 0) && (!(platform_id_len % PLAT_ID_SIZE))) {
389 /*Compare msm-id of the dtb vs board*/
390 current_dtb_info->dt_platform_id = fdt32_to_cpu(((struct plat_id *)platform_prop)->platform_id);
391 dprintf(SPEW, "Board SOC ID = %x | DT SOC ID = %x\n", (board_platform_id() & SOC_MASK),
392 (current_dtb_info->dt_platform_id & SOC_MASK));
393 if ((board_platform_id() & SOC_MASK) == (current_dtb_info->dt_platform_id & SOC_MASK)) {
394 current_dtb_info->dt_match_val |= BIT(SOC_MATCH);
395 } else {
396 dprintf(SPEW, "qcom,msm-id does not match\n");
397 /* If soc doesn't match, don't select dtb */
398 current_dtb_info->dt_match_val = BIT(NONE_MATCH);
399 goto cleanup;
400 }
401 /*Compare soc rev of the dtb vs board*/
402 current_dtb_info->dt_soc_rev = fdt32_to_cpu(((struct plat_id *)platform_prop)->soc_rev);
403 dprintf(SPEW, "Board SOC Rev = %x | DT SOC Rev =%x\n", board_soc_version(),
404 current_dtb_info->dt_soc_rev);
405 if (current_dtb_info->dt_soc_rev == board_soc_version()) {
406 current_dtb_info->dt_match_val |= BIT(VERSION_EXACT_MATCH);
407 } else if (current_dtb_info->dt_soc_rev < board_soc_version()) {
408 current_dtb_info->dt_match_val |= BIT(VERSION_BEST_MATCH);
409 } else if (current_dtb_info->dt_soc_rev) {
410 dprintf(SPEW, "SOC version does not match\n");
411 }
412 /*Compare Foundry Id of the dtb vs Board*/
413 current_dtb_info->dt_foundry_id = fdt32_to_cpu(((struct plat_id *)platform_prop)->platform_id) & FOUNDRY_ID_MASK;
414 dprintf (SPEW, "Board Foundry id = %x | DT Foundry id = %x\n", (board_foundry_id() << PLATFORM_FOUNDRY_SHIFT), current_dtb_info->dt_foundry_id);
415 if (current_dtb_info->dt_foundry_id == (board_foundry_id() << PLATFORM_FOUNDRY_SHIFT)) {
416 current_dtb_info->dt_match_val |= BIT (FOUNDRYID_EXACT_MATCH);
417 } else if (current_dtb_info->dt_foundry_id == 0 ){
418 current_dtb_info->dt_match_val |= BIT (FOUNDRYID_DEFAULT_MATCH);
419 } else {
420 dprintf(SPEW, "soc foundry does not match\n");
421 /* If soc doesn't match, don't select dtb */
422 current_dtb_info->dt_match_val = BIT(NONE_MATCH);
423 goto cleanup;
424 }
425 } else {
426 dprintf(SPEW, "qcom,msm-id does not exist (or) is (%d) not a multiple of (%d)\n", platform_id_len, PLAT_ID_SIZE);
427 }
428
429 /* Get the properties like variant id, subtype from DTB and compare the DTB vs Board */
430 board_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,board-id", &board_id_len);
431 if (board_prop && (board_id_len > 0) && (!(board_id_len % BOARD_ID_SIZE))) {
432 current_dtb_info->dt_variant_id = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id);
433 current_dtb_info->dt_platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->platform_subtype);
434 if (current_dtb_info->dt_platform_subtype == 0)
435 current_dtb_info->dt_platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id) >> PLATFORM_SUBTYPE_SHIFT_ID;
436
437 dprintf(SPEW, "Board variant id = %x | DT variant id = %x\n",board_hardware_id(), current_dtb_info->dt_variant_id);
438
439 current_dtb_info->dt_variant_major = current_dtb_info->dt_variant_id & VARIANT_MAJOR_MASK;
440 current_dtb_info->dt_variant_minor = current_dtb_info->dt_variant_id & VARIANT_MINOR_MASK;
441 current_dtb_info->dt_variant_id = current_dtb_info->dt_variant_id & VARIANT_MASK;
442
443 if (current_dtb_info->dt_variant_id == board_hardware_id()) {
444 current_dtb_info->dt_match_val |= BIT(VARIANT_MATCH);
445 } else if (current_dtb_info->dt_variant_id) {
446 dprintf(SPEW, "qcom,board-id doesnot match\n");
447 /* If board variant doesn't match, don't select dtb */
448 current_dtb_info->dt_match_val = BIT(NONE_MATCH);
449 goto cleanup;
450 }
451
452 if (current_dtb_info->dt_variant_major == (board_target_id() & VARIANT_MAJOR_MASK)) {
453 current_dtb_info->dt_match_val |= BIT(VARIANT_MAJOR_EXACT_MATCH);
454 } else if (current_dtb_info->dt_variant_major < (board_target_id() & VARIANT_MAJOR_MASK)) {
455 current_dtb_info->dt_match_val |= BIT(VARIANT_MAJOR_BEST_MATCH);
456 } else if (current_dtb_info->dt_variant_major) {
457 dprintf(SPEW, "qcom,board-id major version doesnot match\n");
458 }
459
460 if (current_dtb_info->dt_variant_minor == (board_target_id() & VARIANT_MINOR_MASK)) {
461 current_dtb_info->dt_match_val |= BIT(VARIANT_MINOR_EXACT_MATCH);
462 } else if (current_dtb_info->dt_variant_minor < (board_target_id() & VARIANT_MINOR_MASK)) {
463 current_dtb_info->dt_match_val |= BIT(VARIANT_MINOR_BEST_MATCH);
464 } else if (current_dtb_info->dt_variant_minor) {
465 dprintf(SPEW, "qcom,board-id minor version doesnot match\n");
466 }
467
468 dprintf(SPEW, "Board platform subtype = %x | DT platform subtype = %x\n",
469 board_hardware_subtype(), current_dtb_info->dt_platform_subtype);
470 if (current_dtb_info->dt_platform_subtype == board_hardware_subtype()) {
471 current_dtb_info->dt_match_val |= BIT(SUBTYPE_EXACT_MATCH);
472 } else if (current_dtb_info->dt_platform_subtype == 0) {
473 current_dtb_info->dt_match_val |= BIT(SUBTYPE_DEFAULT_MATCH);
474 } else if (current_dtb_info->dt_platform_subtype) {
475 dprintf(SPEW, "subtype id doesnot match\n");
476 /* If board platform doesn't match, don't select dtb */
477 current_dtb_info->dt_match_val = BIT(NONE_MATCH);
478 goto cleanup;
479 }
480 } else {
481 dprintf(SPEW, "qcom,board-id does not exist (or)(%d) is not a multiple of (%d)\n",
482 board_id_len, BOARD_ID_SIZE);
483 }
484
485 /* Get the pmic property from DTB then compare the DTB vs Board */
486 pmic_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,pmic-id", &pmic_id_len);
487 if (pmic_prop && (pmic_id_len > 0) && (!(pmic_id_len % sizeof(struct pmic_id))))
488 {
489 pmic_info curr_pmic_info;
490 pmic_info best_pmic_info;
491 unsigned int pmic_entry_indx;
492 unsigned int pmic_entries_count;
493
494 /* Find all pmic entries count */
495 pmic_entries_count = pmic_id_len/sizeof(struct pmic_id);
496
497 memset(&best_pmic_info, 0, sizeof(pmic_info));
498 for (pmic_entry_indx = 0; pmic_entry_indx < pmic_entries_count; pmic_entry_indx++)
499 {
500 memset(&curr_pmic_info, 0, sizeof(pmic_info));
501
502 /* Read all pmic info */
503 /* Compare with board pmic */
504 for (idx = 0; idx < MAX_PMIC_IDX; idx++)
505 {
506 curr_pmic_info.dt_pmic_model[idx] =
507 fdt32_to_cpu (((struct pmic_id *)pmic_prop)->pmic_version[idx]);
508 dprintf(SPEW, "pmic_data[%u]:%x\n", idx, curr_pmic_info.dt_pmic_model[idx]);
509 curr_pmic_info.dt_pmic_rev[idx] =
510 curr_pmic_info.dt_pmic_model[idx] & PMIC_REV_MASK;
511 curr_pmic_info.dt_pmic_model[idx] =
512 curr_pmic_info.dt_pmic_model[idx] & PMIC_MODEL_MASK;
513
514 /* Compare with board pmic information & Update bit mask */
515 if (curr_pmic_info.dt_pmic_model[idx] == (board_pmic_target(idx) & PMIC_MODEL_MASK))
516 curr_pmic_info.dt_match_val |= BIT (PMIC_MATCH_EXACT_MODEL_IDX0 + idx * PMIC_SHIFT_IDX);
517 else if (curr_pmic_info.dt_pmic_model[idx] == 0)
518 curr_pmic_info.dt_match_val |= BIT (PMIC_MATCH_DEFAULT_MODEL_IDX0 + idx * PMIC_SHIFT_IDX);
519 else
520 {
521 curr_pmic_info.dt_match_val |= BIT (NONE_MATCH);
522 dprintf(SPEW, "PMIC Model doesn't match\n");
523 break; /* go to next pmic entry */
524 }
525
526 if (curr_pmic_info.dt_pmic_rev[idx] == (board_pmic_target(idx) & PMIC_REV_MASK))
527 curr_pmic_info.dt_match_val |= BIT(PMIC_MATCH_EXACT_REV_IDX0 + idx * PMIC_SHIFT_IDX);
528 else if (curr_pmic_info.dt_pmic_rev[idx] < (board_pmic_target(idx) & PMIC_REV_MASK))
529 curr_pmic_info.dt_match_val |= BIT(PMIC_MATCH_BEST_REV_IDX0 + idx * PMIC_SHIFT_IDX);
lijuangf1b8e1d2018-03-01 14:40:37 +0800530 else {
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530531 dprintf(SPEW, "PMIC revision doesn't match\n");
532 break; /* go to next pmic entry */
lijuangf1b8e1d2018-03-01 14:40:37 +0800533 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530534 }
535
536 dprintf(SPEW, "Bestpmicinfo.dtmatchval : %x | cur_pmic_info.dtmatchval: %x\n",
537 best_pmic_info.dt_match_val, curr_pmic_info.dt_match_val);
538
539 /* Update best pmic info, if required */
540 if(best_pmic_info.dt_match_val < curr_pmic_info.dt_match_val)
541 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
542 else if (best_pmic_info.dt_match_val == curr_pmic_info.dt_match_val)
543 {
544 if (best_pmic_info.dt_pmic_rev[PMIC_IDX0] < curr_pmic_info.dt_pmic_rev[PMIC_IDX0])
545 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
546 else if (best_pmic_info.dt_pmic_rev[PMIC_IDX1] < curr_pmic_info.dt_pmic_rev[PMIC_IDX1])
547 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
548 else if (best_pmic_info.dt_pmic_rev[PMIC_IDX2] < curr_pmic_info.dt_pmic_rev[PMIC_IDX2])
549 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
550 else if (best_pmic_info.dt_pmic_rev[PMIC_IDX3] < curr_pmic_info.dt_pmic_rev[PMIC_IDX3])
551 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
552 }
553
554 /* Increment to next pmic entry */
555 pmic_prop += sizeof (struct pmic_id);
556 }
557
558 dprintf(SPEW, "Best pmic info 0x%0x/0x%x/0x%x/0x%0x for current dt\n",
559 best_pmic_info.dt_pmic_model[PMIC_IDX0],
560 best_pmic_info.dt_pmic_model[PMIC_IDX1],
561 best_pmic_info.dt_pmic_model[PMIC_IDX2],
562 best_pmic_info.dt_pmic_model[PMIC_IDX3]);
563
564 current_dtb_info->dt_match_val |= best_pmic_info.dt_match_val;
565 current_dtb_info->dt_pmic_rev[PMIC_IDX0] = best_pmic_info.dt_pmic_rev[PMIC_IDX0];
566 current_dtb_info->dt_pmic_model[PMIC_IDX0] = best_pmic_info.dt_pmic_model[PMIC_IDX0];
567 current_dtb_info->dt_pmic_rev[PMIC_IDX1] = best_pmic_info.dt_pmic_rev[PMIC_IDX1];
568 current_dtb_info->dt_pmic_model[PMIC_IDX1] = best_pmic_info.dt_pmic_model[PMIC_IDX1];
569 current_dtb_info->dt_pmic_rev[PMIC_IDX2] = best_pmic_info.dt_pmic_rev[PMIC_IDX2];
570 current_dtb_info->dt_pmic_model[PMIC_IDX2] = best_pmic_info.dt_pmic_model[PMIC_IDX2];
571 current_dtb_info->dt_pmic_rev[PMIC_IDX3] = best_pmic_info.dt_pmic_rev[PMIC_IDX3];
572 current_dtb_info->dt_pmic_model[PMIC_IDX3] = best_pmic_info.dt_pmic_model[PMIC_IDX3];
573 }
574 else
575 {
576 dprintf(SPEW, "qcom,pmic-id does not exit (or) is (%d) not a multiple of (%d)\n",
577 pmic_id_len, PMIC_ID_SIZE);
578 }
579
580cleanup:
581 if (current_dtb_info->dt_match_val & BIT(exact_match)) {
lijuang0cce8bf2018-08-23 10:56:42 +0800582 if (best_dtb_info->dt_match_val < current_dtb_info->dt_match_val) {
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530583 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
lijuang0cce8bf2018-08-23 10:56:42 +0800584 find_best_match = true;
585 } else if (best_dtb_info->dt_match_val == current_dtb_info->dt_match_val) {
586 find_best_match = true;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530587 if (best_dtb_info->dt_soc_rev < current_dtb_info->dt_soc_rev)
588 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
589 else if (best_dtb_info->dt_variant_major < current_dtb_info->dt_variant_major)
590 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
591 else if (best_dtb_info->dt_variant_minor < current_dtb_info->dt_variant_minor)
592 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
593 else if (best_dtb_info->dt_pmic_rev[0] < current_dtb_info->dt_pmic_rev[0])
594 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
595 else if (best_dtb_info->dt_pmic_rev[1] < current_dtb_info->dt_pmic_rev[1])
596 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
597 else if (best_dtb_info->dt_pmic_rev[2] < current_dtb_info->dt_pmic_rev[2])
598 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
599 else if (best_dtb_info->dt_pmic_rev[3] < current_dtb_info->dt_pmic_rev[3])
600 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
lijuang0cce8bf2018-08-23 10:56:42 +0800601 else
602 find_best_match = false;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530603 }
604 }
lijuang0cce8bf2018-08-23 10:56:42 +0800605
606 return find_best_match;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530607}
608
609void *get_soc_dtb(void *kernel, uint32_t kernel_size, uint32_t dtb_offset)
610{
611 uintptr_t kernel_end_offset = (uintptr_t)kernel + kernel_size;
612 void *dtb = NULL;
613 struct fdt_header dtb_header;
614 uint32_t dtb_size = 0;
615 dt_info cur_dtb_info = {0};
616 dt_info best_dtb_info = {0};
617
618 if (!dtb_offset){
619 dprintf(CRITICAL, "DTB offset is NULL\n");
620 return NULL;
621 }
622 if (((uintptr_t)kernel + (uintptr_t)dtb_offset) < (uintptr_t)kernel) {
623 return NULL;
624 }
625 dtb = kernel + dtb_offset;
626 while (((uintptr_t)dtb + sizeof(struct fdt_header)) < (uintptr_t)kernel_end_offset) {
627 /* the DTB could be unaligned, so extract the header,
628 * and operate on it separately */
629 memscpy(&dtb_header, sizeof(struct fdt_header), dtb, sizeof(struct fdt_header));
630 dtb_size = fdt_totalsize((const void *)&dtb_header);
631 if (fdt_check_header((const void *)&dtb_header) != 0 ||
632 fdt_check_header_ext((void *)&dtb_header) != 0 ||
633 ((uintptr_t)dtb + dtb_size < (uintptr_t)dtb) ||
634 ((uintptr_t)dtb + dtb_size > (uintptr_t)kernel_end_offset))
635 break;
636
637 cur_dtb_info.dtb = dtb;
638 dtb_read_find_match(&cur_dtb_info, &best_dtb_info, SOC_MATCH);
639 if (cur_dtb_info.dt_match_val) {
640 if (cur_dtb_info.dt_match_val & BIT(SOC_MATCH)) {
641 if (check_all_bits_set(cur_dtb_info.dt_match_val)) {
642 dprintf(CRITICAL, "Exact DTB match found. dtbo search is not required\n");
643 dtbo_needed = false;
644 }
645 }
646 }
647 dprintf(SPEW, "Best Match DTB VAL = %x\n", best_dtb_info.dt_match_val);
648 dtb += dtb_size;
649 }
650 if (!best_dtb_info.dtb) {
651 dprintf(CRITICAL, "No match found for soc dtb type\n");
652 return NULL;
653 }
654 return best_dtb_info.dtb;
655}
656
657void *get_board_dtb(void *dtbo_image_buf)
658{
659 struct dtbo_table_hdr *dtbo_table_header = dtbo_image_buf;
660 struct dtbo_table_entry *dtb_table_entry = NULL;
661 uint32_t dtbo_count = 0;
662 void *board_dtb = NULL;
663 uint32_t dtbo_table_entries_count = 0;
664 uint32_t first_dtbo_table_entry_offset = 0;
665 struct fdt_header dtb_header;
666 uint32_t dtb_size = 0;
667 dt_info cur_dtb_info = {0};
668 dt_info best_dtb_info = {0};
lijuang0cce8bf2018-08-23 10:56:42 +0800669 boolean find_best_dtb = false;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530670
671 if (!dtbo_image_buf) {
672 dprintf(CRITICAL, "dtbo image buffer is NULL\n");
673 return NULL;
674 }
675
676 first_dtbo_table_entry_offset = fdt32_to_cpu(dtbo_table_header->dt_entry_offset);
677 if ((uintptr_t)dtbo_image_buf > ((uintptr_t)dtbo_image_buf + (uintptr_t)first_dtbo_table_entry_offset))
678 {
679 dprintf(CRITICAL, "dtbo table entry offset is invalid\n");
680 return NULL;
681 }
682 dtb_table_entry = (struct dtbo_table_entry *)(dtbo_image_buf + first_dtbo_table_entry_offset);
683 dtbo_table_entries_count = fdt32_to_cpu(dtbo_table_header->dt_entry_count);
684 for (dtbo_count = 0; dtbo_count < dtbo_table_entries_count; dtbo_count++) {
685 board_dtb = dtbo_image_buf + fdt32_to_cpu(dtb_table_entry->dt_offset);
686 /* The DTB could be unaligned, so extract the header,
687 * and operate on it separately */
688 memscpy(&dtb_header, sizeof(struct fdt_header), board_dtb, sizeof(struct fdt_header));
689 dtb_size = fdt_totalsize((const void *)&dtb_header);
690 if (fdt_check_header((const void *)&dtb_header) != 0 ||
691 fdt_check_header_ext((void *)&dtb_header) != 0 ||
692 ((uintptr_t)board_dtb + dtb_size < (uintptr_t)board_dtb)) {
693 dprintf(CRITICAL, "No valid board dtb found\n");
694 break;
695 }
696 dprintf(SPEW, "Valid board dtb is found\n");
697 cur_dtb_info.dtb = board_dtb;
lijuang0cce8bf2018-08-23 10:56:42 +0800698 find_best_dtb = dtb_read_find_match(&cur_dtb_info, &best_dtb_info, VARIANT_MATCH);
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530699 dprintf(SPEW, "dtbo count = %u local_board_dt_match =%x\n",dtbo_count, cur_dtb_info.dt_match_val);
700 dtb_table_entry++;
lijuang0cce8bf2018-08-23 10:56:42 +0800701
702 if (find_best_dtb) {
703 dtbo_idx = dtbo_count;
704 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530705 }
706 if (!best_dtb_info.dtb) {
707 dprintf(CRITICAL, "Unable to find the board dtb\n");
708 return NULL;
709 }
710 return best_dtb_info.dtb;
711}
712
Lijuan Gao9f152862014-08-18 13:45:24 +0800713static void insert_dt_entry_in_queue(struct dt_entry_node *dt_list, struct dt_entry_node *dt_node_member)
714{
715 list_add_tail(&dt_list->node, &dt_node_member->node);
716}
717
718static void dt_entry_list_delete(struct dt_entry_node *dt_node_member)
719{
720 if (list_in_list(&dt_node_member->node)) {
721 list_delete(&dt_node_member->node);
722 free(dt_node_member->dt_entry_m);
723 free(dt_node_member);
724 }
725}
726
727static int dev_tree_compatible(void *dtb, uint32_t dtb_size, struct dt_entry_node *dtb_list)
Dima Zavinc46f8382013-05-03 12:23:06 -0700728{
729 int root_offset;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700730 const void *prop = NULL;
731 const char *plat_prop = NULL;
732 const char *board_prop = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800733 const char *pmic_prop = NULL;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700734 char *model = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800735 struct dt_entry *cur_dt_entry;
736 struct dt_entry *dt_entry_array = NULL;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700737 struct board_id *board_data = NULL;
738 struct plat_id *platform_data = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800739 struct pmic_id *pmic_data = NULL;
Dima Zavinc46f8382013-05-03 12:23:06 -0700740 int len;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700741 int len_board_id;
742 int len_plat_id;
743 int min_plat_id_len = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800744 int len_pmic_id;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700745 uint32_t dtb_ver;
746 uint32_t num_entries = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800747 uint32_t i, j, k, n;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700748 uint32_t msm_data_count;
749 uint32_t board_data_count;
Lijuan Gao9f152862014-08-18 13:45:24 +0800750 uint32_t pmic_data_count;
Dima Zavinc46f8382013-05-03 12:23:06 -0700751
752 root_offset = fdt_path_offset(dtb, "/");
753 if (root_offset < 0)
754 return false;
755
756 prop = fdt_getprop(dtb, root_offset, "model", &len);
757 if (prop && len > 0) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700758 model = (char *) malloc(sizeof(char) * len);
759 ASSERT(model);
760 strlcpy(model, prop, len);
Dima Zavinc46f8382013-05-03 12:23:06 -0700761 } else {
vijay kumar89d36d82014-06-30 19:32:18 +0530762 dprintf(INFO, "model does not exist in device tree\n");
Dima Zavinc46f8382013-05-03 12:23:06 -0700763 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800764 /* Find the pmic-id prop from DTB , if pmic-id is present then
765 * the DTB is version 3, otherwise find the board-id prop from DTB ,
766 * if board-id is present then the DTB is version 2 */
767 pmic_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,pmic-id", &len_pmic_id);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700768 board_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,board-id", &len_board_id);
Lijuan Gao9f152862014-08-18 13:45:24 +0800769 if (pmic_prop && (len_pmic_id > 0) && board_prop && (len_board_id > 0)) {
770 if ((len_pmic_id % PMIC_ID_SIZE) || (len_board_id % BOARD_ID_SIZE))
771 {
772 dprintf(CRITICAL, "qcom,pmic-id(%d) or qcom,board-id(%d) in device tree is not a multiple of (%d %d)\n",
773 len_pmic_id, len_board_id, PMIC_ID_SIZE, BOARD_ID_SIZE);
774 return false;
775 }
776 dtb_ver = DEV_TREE_VERSION_V3;
777 min_plat_id_len = PLAT_ID_SIZE;
778 } else if (board_prop && len_board_id > 0) {
vijay kumar89d36d82014-06-30 19:32:18 +0530779 if (len_board_id % BOARD_ID_SIZE)
780 {
781 dprintf(CRITICAL, "qcom,board-id in device tree is (%d) not a multiple of (%d)\n",
782 len_board_id, BOARD_ID_SIZE);
783 return false;
784 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700785 dtb_ver = DEV_TREE_VERSION_V2;
786 min_plat_id_len = PLAT_ID_SIZE;
Lijuan Gao9f152862014-08-18 13:45:24 +0800787 } else {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700788 dtb_ver = DEV_TREE_VERSION_V1;
789 min_plat_id_len = DT_ENTRY_V1_SIZE;
790 }
791
792 /* Get the msm-id prop from DTB */
793 plat_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,msm-id", &len_plat_id);
794 if (!plat_prop || len_plat_id <= 0) {
Dima Zavinc46f8382013-05-03 12:23:06 -0700795 dprintf(INFO, "qcom,msm-id entry not found\n");
796 return false;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700797 } else if (len_plat_id % min_plat_id_len) {
798 dprintf(INFO, "qcom,msm-id in device tree is (%d) not a multiple of (%d)\n",
799 len_plat_id, min_plat_id_len);
Dima Zavinc46f8382013-05-03 12:23:06 -0700800 return false;
801 }
Dima Zavinc46f8382013-05-03 12:23:06 -0700802
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700803 /*
804 * If DTB version is '1' look for <x y z> pair in the DTB
805 * x: platform_id
806 * y: variant_id
807 * z: SOC rev
808 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800809 if (dtb_ver == DEV_TREE_VERSION_V1) {
810 cur_dt_entry = (struct dt_entry *)
811 malloc(sizeof(struct dt_entry));
Dima Zavinc46f8382013-05-03 12:23:06 -0700812
Lijuan Gao9f152862014-08-18 13:45:24 +0800813 if (!cur_dt_entry) {
814 dprintf(CRITICAL, "Out of memory\n");
815 return false;
816 }
817 memset(cur_dt_entry, 0, sizeof(struct dt_entry));
818
819 while (len_plat_id) {
820 cur_dt_entry->platform_id = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->platform_id);
821 cur_dt_entry->variant_id = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->variant_id);
822 cur_dt_entry->soc_rev = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->soc_rev);
823 cur_dt_entry->board_hw_subtype =
824 fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->variant_id) >> 0x18;
825 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
826 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
827 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
828 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
829 cur_dt_entry->offset = (uint32_t)dtb;
830 cur_dt_entry->size = dtb_size;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700831
832 dprintf(SPEW, "Found an appended flattened device tree (%s - %u %u 0x%x)\n",
Lijuan Gao9f152862014-08-18 13:45:24 +0800833 *model ? model : "unknown",
834 cur_dt_entry->platform_id, cur_dt_entry->variant_id, cur_dt_entry->soc_rev);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700835
Lijuan Gao9f152862014-08-18 13:45:24 +0800836 if (platform_dt_absolute_match(cur_dt_entry, dtb_list)) {
837 dprintf(SPEW, "Device tree exact match the board: <%u %u 0x%x> != <%u %u 0x%x>\n",
838 cur_dt_entry->platform_id,
839 cur_dt_entry->variant_id,
840 cur_dt_entry->soc_rev,
841 board_platform_id(),
842 board_hardware_id(),
843 board_soc_version());
844
845 } else {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700846 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 +0800847 cur_dt_entry->platform_id,
848 cur_dt_entry->variant_id,
849 cur_dt_entry->soc_rev,
850 board_platform_id(),
851 board_hardware_id(),
852 board_soc_version());
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700853 plat_prop += DT_ENTRY_V1_SIZE;
854 len_plat_id -= DT_ENTRY_V1_SIZE;
855 continue;
856 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700857 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800858 free(cur_dt_entry);
859
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700860 }
861 /*
Lijuan Gao9f152862014-08-18 13:45:24 +0800862 * If DTB Version is '3' then we have split DTB with board & msm data & pmic
863 * populated saperately in board-id & msm-id & pmic-id prop respectively.
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700864 * Extract the data & prepare a look up table
865 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800866 else if (dtb_ver == DEV_TREE_VERSION_V2 || dtb_ver == DEV_TREE_VERSION_V3) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700867 board_data_count = (len_board_id / BOARD_ID_SIZE);
868 msm_data_count = (len_plat_id / PLAT_ID_SIZE);
Lijuan Gao9f152862014-08-18 13:45:24 +0800869 /* If dtb version is v2.0, the pmic_data_count will be <= 0 */
870 pmic_data_count = (len_pmic_id / PMIC_ID_SIZE);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700871
Lijuan Gao9f152862014-08-18 13:45:24 +0800872 /* If we are using dtb v3.0, then we have split board, msm & pmic data in the DTB
873 * If we are using dtb v2.0, then we have split board & msmdata in the DTB
874 */
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700875 board_data = (struct board_id *) malloc(sizeof(struct board_id) * (len_board_id / BOARD_ID_SIZE));
876 ASSERT(board_data);
877 platform_data = (struct plat_id *) malloc(sizeof(struct plat_id) * (len_plat_id / PLAT_ID_SIZE));
878 ASSERT(platform_data);
Lijuan Gao9f152862014-08-18 13:45:24 +0800879 if (dtb_ver == DEV_TREE_VERSION_V3) {
880 pmic_data = (struct pmic_id *) malloc(sizeof(struct pmic_id) * (len_pmic_id / PMIC_ID_SIZE));
881 ASSERT(pmic_data);
882 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700883 i = 0;
884
885 /* Extract board data from DTB */
Lijuan Gao9f152862014-08-18 13:45:24 +0800886 for(i = 0 ; i < board_data_count; i++) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700887 board_data[i].variant_id = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id);
888 board_data[i].platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->platform_subtype);
Lijuan Gao9f152862014-08-18 13:45:24 +0800889 /* For V2/V3 version of DTBs we have platform version field as part
890 * of variant ID, in such case the subtype will be mentioned as 0x0
891 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
892 * SS -- Subtype
893 * PM -- Platform major version
894 * Pm -- Platform minor version
895 * PH -- Platform hardware CDP/MTP
896 * In such case to make it compatible with LK algorithm move the subtype
897 * from variant_id to subtype field
898 */
899 if (board_data[i].platform_subtype == 0)
900 board_data[i].platform_subtype =
901 fdt32_to_cpu(((struct board_id *)board_prop)->variant_id) >> 0x18;
902
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700903 len_board_id -= sizeof(struct board_id);
904 board_prop += sizeof(struct board_id);
905 }
906
907 /* Extract platform data from DTB */
Lijuan Gao9f152862014-08-18 13:45:24 +0800908 for(i = 0 ; i < msm_data_count; i++) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700909 platform_data[i].platform_id = fdt32_to_cpu(((struct plat_id *)plat_prop)->platform_id);
910 platform_data[i].soc_rev = fdt32_to_cpu(((struct plat_id *)plat_prop)->soc_rev);
911 len_plat_id -= sizeof(struct plat_id);
912 plat_prop += sizeof(struct plat_id);
913 }
914
Lijuan Gao9f152862014-08-18 13:45:24 +0800915 if (dtb_ver == DEV_TREE_VERSION_V3 && pmic_prop) {
916 /* Extract pmic data from DTB */
917 for(i = 0 ; i < pmic_data_count; i++) {
918 pmic_data[i].pmic_version[0]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[0]);
919 pmic_data[i].pmic_version[1]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[1]);
920 pmic_data[i].pmic_version[2]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[2]);
921 pmic_data[i].pmic_version[3]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[3]);
922 len_pmic_id -= sizeof(struct pmic_id);
923 pmic_prop += sizeof(struct pmic_id);
924 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700925
Lijuan Gao9f152862014-08-18 13:45:24 +0800926 /* We need to merge board & platform data into dt entry structure */
927 num_entries = msm_data_count * board_data_count * pmic_data_count;
928 } else {
929 /* We need to merge board & platform data into dt entry structure */
930 num_entries = msm_data_count * board_data_count;
931 }
vijay kumar89d36d82014-06-30 19:32:18 +0530932
Lijuan Gao9f152862014-08-18 13:45:24 +0800933 if ((((uint64_t)msm_data_count * (uint64_t)board_data_count * (uint64_t)pmic_data_count) !=
934 msm_data_count * board_data_count * pmic_data_count) ||
935 (((uint64_t)msm_data_count * (uint64_t)board_data_count) != msm_data_count * board_data_count)) {
936
937 free(board_data);
938 free(platform_data);
939 if (pmic_data)
940 free(pmic_data);
941 if (model)
942 free(model);
943 return false;
944 }
945
946 dt_entry_array = (struct dt_entry*) malloc(sizeof(struct dt_entry) * num_entries);
947 ASSERT(dt_entry_array);
948
949 /* If we have '<X>; <Y>; <Z>' as platform data & '<A>; <B>; <C>' as board data.
950 * Then dt entry should look like
951 * <X ,A >;<X, B>;<X, C>;
952 * <Y ,A >;<Y, B>;<Y, C>;
953 * <Z ,A >;<Z, B>;<Z, C>;
954 */
955 i = 0;
956 k = 0;
957 n = 0;
958 for (i = 0; i < msm_data_count; i++) {
959 for (j = 0; j < board_data_count; j++) {
960 if (dtb_ver == DEV_TREE_VERSION_V3 && pmic_prop) {
961 for (n = 0; n < pmic_data_count; n++) {
962 dt_entry_array[k].platform_id = platform_data[i].platform_id;
963 dt_entry_array[k].soc_rev = platform_data[i].soc_rev;
964 dt_entry_array[k].variant_id = board_data[j].variant_id;
965 dt_entry_array[k].board_hw_subtype = board_data[j].platform_subtype;
966 dt_entry_array[k].pmic_rev[0]= pmic_data[n].pmic_version[0];
967 dt_entry_array[k].pmic_rev[1]= pmic_data[n].pmic_version[1];
968 dt_entry_array[k].pmic_rev[2]= pmic_data[n].pmic_version[2];
969 dt_entry_array[k].pmic_rev[3]= pmic_data[n].pmic_version[3];
970 dt_entry_array[k].offset = (uint32_t)dtb;
971 dt_entry_array[k].size = dtb_size;
972 k++;
973 }
974
975 } else {
976 dt_entry_array[k].platform_id = platform_data[i].platform_id;
977 dt_entry_array[k].soc_rev = platform_data[i].soc_rev;
978 dt_entry_array[k].variant_id = board_data[j].variant_id;
979 dt_entry_array[k].board_hw_subtype = board_data[j].platform_subtype;
980 dt_entry_array[k].pmic_rev[0]= board_pmic_target(0);
981 dt_entry_array[k].pmic_rev[1]= board_pmic_target(1);
982 dt_entry_array[k].pmic_rev[2]= board_pmic_target(2);
983 dt_entry_array[k].pmic_rev[3]= board_pmic_target(3);
984 dt_entry_array[k].offset = (uint32_t)dtb;
985 dt_entry_array[k].size = dtb_size;
vijay kumar89d36d82014-06-30 19:32:18 +0530986 k++;
987 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700988 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800989 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700990
Lijuan Gao9f152862014-08-18 13:45:24 +0800991 for (i=0 ;i < num_entries; i++) {
992 dprintf(SPEW, "Found an appended flattened device tree (%s - %u %u %u 0x%x)\n",
993 *model ? model : "unknown",
994 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 +0530995
Lijuan Gao9f152862014-08-18 13:45:24 +0800996 if (platform_dt_absolute_match(&(dt_entry_array[i]), dtb_list)) {
997 dprintf(SPEW, "Device tree exact match the board: <%u %u %u 0x%x> == <%u %u %u 0x%x>\n",
998 dt_entry_array[i].platform_id,
999 dt_entry_array[i].variant_id,
1000 dt_entry_array[i].soc_rev,
1001 dt_entry_array[i].board_hw_subtype,
1002 board_platform_id(),
1003 board_hardware_id(),
1004 board_hardware_subtype(),
1005 board_soc_version());
vijay kumar89d36d82014-06-30 19:32:18 +05301006
Lijuan Gao9f152862014-08-18 13:45:24 +08001007 } else {
1008 dprintf(SPEW, "Device tree's msm_id doesn't match the board: <%u %u %u 0x%x> != <%u %u %u 0x%x>\n",
1009 dt_entry_array[i].platform_id,
1010 dt_entry_array[i].variant_id,
1011 dt_entry_array[i].soc_rev,
1012 dt_entry_array[i].board_hw_subtype,
1013 board_platform_id(),
1014 board_hardware_id(),
1015 board_hardware_subtype(),
1016 board_soc_version());
Channagoud Kadabia4dbe332013-09-05 17:44:11 -07001017 }
1018 }
Lijuan Gao9f152862014-08-18 13:45:24 +08001019
1020 free(board_data);
1021 free(platform_data);
1022 if (pmic_data)
1023 free(pmic_data);
1024 free(dt_entry_array);
Dima Zavinc46f8382013-05-03 12:23:06 -07001025 }
Lijuan Gao9f152862014-08-18 13:45:24 +08001026 if (model)
vijay kumar89d36d82014-06-30 19:32:18 +05301027 free(model);
Lijuan Gao9f152862014-08-18 13:45:24 +08001028 return true;
Dima Zavinc46f8382013-05-03 12:23:06 -07001029}
1030
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301031/* function to handle the overlay in independent thread */
1032static int dtb_overlay_handler(void *args)
1033{
1034 dprintf(SPEW, "thread %s() started\n", __func__);
1035
1036 soc_dtb_hdr = ufdt_install_blob(soc_dtb, fdt_totalsize(soc_dtb));
1037 if(!soc_dtb_hdr)
1038 {
1039 dprintf(CRITICAL, "ERROR: Install Blob failed\n");
1040 ret = DTBO_ERROR;
1041 goto out;
1042 }
1043 final_dtb_hdr = ufdt_apply_overlay(soc_dtb_hdr, fdt_totalsize(soc_dtb_hdr),board_dtb,
1044 fdt_totalsize(board_dtb));
1045 if (!final_dtb_hdr)
1046 {
1047 dprintf(CRITICAL, "ERROR: UFDT apply overlay failed\n");
1048 ret = DTBO_ERROR;
1049 goto out;
1050 }
1051out:
1052 /* This flag can only be updated here, hence it is not protected */
1053 event_signal(&dtbo_event, true);
1054 thread_exit(0);
1055 return 0;
1056}
1057
1058/*
1059 * Function to check and form new dtb with Overlay support.
1060*/
1061dtbo_error dev_tree_appended_with_dtbo(void *kernel, uint32_t kernel_size,
1062 uint32_t dtb_offset, void *tags)
1063{
1064 void *dtbo_image_buf = NULL;
Mayank Groverb61c0c22018-09-04 15:09:32 +05301065 uint32_t dtbo_image_sz = 0;
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301066
Mayank Grover302432a2017-12-08 17:18:58 +05301067 bs_set_timestamp(BS_DTB_OVERLAY_START);
Mayank Groverb61c0c22018-09-04 15:09:32 +05301068 ret = load_validate_dtbo_image(&dtbo_image_buf, &dtbo_image_sz);
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301069 if (ret == DTBO_SUCCESS)
1070 {
1071 final_dtb_hdr = soc_dtb = get_soc_dtb(kernel,
1072 kernel_size, dtb_offset);
1073 if(!soc_dtb)
1074 {
1075 ret = DTBO_ERROR;
1076 goto out;
1077 }
1078
1079 if (dtbo_needed)
1080 {
1081 board_dtb = get_board_dtb(dtbo_image_buf);
1082 if(!board_dtb)
1083 {
1084 ret = DTBO_ERROR;
1085 goto out;
1086 }
1087
1088 if((ADD_OF((fdt_totalsize(soc_dtb)), (fdt_totalsize(board_dtb)))) > MAX_DTBO_SZ)
1089 {
1090 dprintf(CRITICAL, "ERROR: dtb greater than max supported.\n");
1091 ret = DTBO_ERROR;
1092 goto out;
1093 }
1094
1095 /*
1096 spawn a seperate thread for dtbo overlay with indpendent,
1097 stack to avoid issues with stack corruption seen during flattening,
1098 of dtb in overlay functionality
1099 */
1100 {
1101 thread_t *thr = NULL;
1102 event_init(&dtbo_event, 0, EVENT_FLAG_AUTOUNSIGNAL);
1103 thr = thread_create("dtb_overlay", dtb_overlay_handler, 0,
1104 DEFAULT_PRIORITY, DTBO_STACK_SIZE);
1105 if (!thr)
1106 {
1107 dprintf(CRITICAL, "ERROR: Failed to create DTBO thread.\n");
1108 ret = DTBO_ERROR;
1109 goto out;
1110 }
1111 thread_resume(thr);
1112
1113 /* block current thread, untill woken up by dtb_overlay_handler. */
1114 event_wait(&dtbo_event);
1115
1116 /* ret is updated by dtb overlay thread, in case of error */
1117 if(ret == DTBO_ERROR)
1118 {
1119 goto out;
1120 }
1121 } /* dtbo_overlay_handler exited */
1122
1123 }
1124 memscpy(tags, fdt_totalsize(final_dtb_hdr), final_dtb_hdr,
1125 fdt_totalsize(final_dtb_hdr));
Mayank Grover71f63862018-05-03 17:06:41 +05301126 dprintf(INFO, "DTB overlay is successful\n");
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301127 }
1128 else
1129 {
Mayank Grover71f63862018-05-03 17:06:41 +05301130 dprintf(INFO, "ERROR: DTBO read is not valid\n DTB Overlay failed.\n");
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301131 ret = DTBO_NOT_SUPPORTED;
1132 }
1133out:
Mayank Grover302432a2017-12-08 17:18:58 +05301134 bs_set_timestamp(BS_DTB_OVERLAY_END);
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301135 return ret;
1136}
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001137/*
Dima Zavin77e41f32013-03-06 16:10:43 -08001138 * Will relocate the DTB to the tags addr if the device tree is found and return
1139 * its address
1140 *
1141 * Arguments: kernel - Start address of the kernel loaded in RAM
1142 * tags - Start address of the tags loaded in RAM
Channagoud Kadabi704cd562013-04-25 15:19:59 -07001143 * kernel_size - Size of the kernel in bytes
1144 *
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001145 * Return Value: DTB address : If appended device tree is found
Dima Zavin77e41f32013-03-06 16:10:43 -08001146 * 'NULL' : Otherwise
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001147 */
Matthew Qinbb7923d2015-02-09 10:56:09 +08001148void *dev_tree_appended(void *kernel, uint32_t kernel_size, uint32_t dtb_offset, void *tags)
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001149{
Parth Dixit97e47bb2016-03-07 17:20:44 +05301150 uintptr_t kernel_end = (uintptr_t)kernel + kernel_size;
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001151 uint32_t app_dtb_offset = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +08001152 void *dtb = NULL;
Shashank Mittalc0f10282013-07-15 14:53:31 -07001153 void *bestmatch_tag = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +08001154 struct dt_entry *best_match_dt_entry = NULL;
Shashank Mittalc0f10282013-07-15 14:53:31 -07001155 uint32_t bestmatch_tag_size;
Lijuan Gao9f152862014-08-18 13:45:24 +08001156 struct dt_entry_node *dt_entry_queue = NULL;
1157 struct dt_entry_node *dt_node_tmp1 = NULL;
1158 struct dt_entry_node *dt_node_tmp2 = NULL;
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301159 dtbo_error ret = DTBO_NOT_SUPPORTED;
1160
lijuangdc1b5422018-05-07 17:12:59 +08001161 if (dtb_offset)
1162 app_dtb_offset = dtb_offset;
1163 else
1164 memcpy((void*) &app_dtb_offset, (void*) (kernel + DTB_OFFSET), sizeof(uint32_t));
1165
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301166 /* Check for dtbo support */
lijuangdc1b5422018-05-07 17:12:59 +08001167 ret = dev_tree_appended_with_dtbo(kernel, kernel_size, app_dtb_offset, tags);
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301168 if (ret == DTBO_SUCCESS)
1169 return tags;
1170 else if (ret == DTBO_ERROR)
1171 return NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +08001172
Lijuan Gao9f152862014-08-18 13:45:24 +08001173 /* Initialize the dtb entry node*/
1174 dt_entry_queue = (struct dt_entry_node *)
1175 malloc(sizeof(struct dt_entry_node));
1176
1177 if (!dt_entry_queue) {
1178 dprintf(CRITICAL, "Out of memory\n");
1179 return NULL;
1180 }
1181 list_initialize(&dt_entry_queue->node);
1182
vijay kumare2a5ea82014-06-25 12:24:14 +05301183 if (((uintptr_t)kernel + (uintptr_t)app_dtb_offset) < (uintptr_t)kernel) {
1184 return NULL;
1185 }
Parth Dixit97e47bb2016-03-07 17:20:44 +05301186 dtb = (void *)((uintptr_t)kernel + app_dtb_offset);
1187
vijay kumare2a5ea82014-06-25 12:24:14 +05301188 while (((uintptr_t)dtb + sizeof(struct fdt_header)) < (uintptr_t)kernel_end) {
Dima Zavinc46f8382013-05-03 12:23:06 -07001189 struct fdt_header dtb_hdr;
1190 uint32_t dtb_size;
Dima Zavin77e41f32013-03-06 16:10:43 -08001191
Dima Zavinc46f8382013-05-03 12:23:06 -07001192 /* the DTB could be unaligned, so extract the header,
1193 * and operate on it separately */
1194 memcpy(&dtb_hdr, dtb, sizeof(struct fdt_header));
1195 if (fdt_check_header((const void *)&dtb_hdr) != 0 ||
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +05301196 fdt_check_header_ext((const void *)&dtb_hdr) != 0 ||
vijay kumare2a5ea82014-06-25 12:24:14 +05301197 ((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) < (uintptr_t)dtb) ||
1198 ((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) > (uintptr_t)kernel_end))
Dima Zavinc46f8382013-05-03 12:23:06 -07001199 break;
1200 dtb_size = fdt_totalsize(&dtb_hdr);
1201
Lijuan Gao9f152862014-08-18 13:45:24 +08001202 dev_tree_compatible(dtb, dtb_size, dt_entry_queue);
Dima Zavinc46f8382013-05-03 12:23:06 -07001203
1204 /* goto the next device tree if any */
1205 dtb += dtb_size;
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001206 }
Dima Zavinc46f8382013-05-03 12:23:06 -07001207
Lijuan Gao9f152862014-08-18 13:45:24 +08001208 best_match_dt_entry = platform_dt_match_best(dt_entry_queue);
1209 if (best_match_dt_entry){
1210 bestmatch_tag = (void *)best_match_dt_entry->offset;
1211 bestmatch_tag_size = best_match_dt_entry->size;
1212 dprintf(INFO, "Best match DTB tags %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1213 best_match_dt_entry->platform_id, best_match_dt_entry->variant_id,
1214 best_match_dt_entry->board_hw_subtype, best_match_dt_entry->soc_rev,
1215 best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],
1216 best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],
1217 best_match_dt_entry->offset, best_match_dt_entry->size);
1218 dprintf(INFO, "Using pmic info 0x%0x/0x%x/0x%x/0x%0x for device 0x%0x/0x%x/0x%x/0x%0x\n",
1219 best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],
1220 best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],
1221 board_pmic_target(0), board_pmic_target(1),
1222 board_pmic_target(2), board_pmic_target(3));
1223 }
1224 /* free queue's memory */
1225 list_for_every_entry(&dt_entry_queue->node, dt_node_tmp1, dt_node, node) {
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001226 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001227 dt_entry_list_delete(dt_node_tmp1);
1228 dt_node_tmp1 = dt_node_tmp2;
1229 }
1230
Shashank Mittalc0f10282013-07-15 14:53:31 -07001231 if(bestmatch_tag) {
Parth Dixitc2f0cb92016-03-10 10:40:14 +05301232 if (check_aboot_addr_range_overlap((uintptr_t)tags, bestmatch_tag_size)) {
1233 dprintf(CRITICAL, "Tags addresses overlap with aboot addresses.\n");
1234 return NULL;
1235 }
Shashank Mittalc0f10282013-07-15 14:53:31 -07001236 memcpy(tags, bestmatch_tag, bestmatch_tag_size);
1237 /* clear out the old DTB magic so kernel doesn't find it */
1238 *((uint32_t *)(kernel + app_dtb_offset)) = 0;
1239 return tags;
1240 }
1241
Dima Zavinc46f8382013-05-03 12:23:06 -07001242 dprintf(CRITICAL, "DTB offset is incorrect, kernel image does not have appended DTB\n");
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001243
David Ng59c4a782015-05-14 15:51:44 -07001244 dprintf(INFO, "Device info 0x%08x/%08x/0x%08x/%u, pmic 0x%0x/0x%x/0x%x/0x%0x\n",
1245 board_platform_id(), board_soc_version(),
1246 board_target_id(), board_hardware_subtype(),
1247 board_pmic_target(0), board_pmic_target(1),
1248 board_pmic_target(2), board_pmic_target(3));
Dima Zavin77e41f32013-03-06 16:10:43 -08001249 return NULL;
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001250}
1251
Joel Kingaa335dc2013-06-03 16:11:08 -07001252/* Returns 0 if the device tree is valid. */
Deepa Dinamani87252952013-09-09 13:58:27 -07001253int dev_tree_validate(struct dt_table *table, unsigned int page_size, uint32_t *dt_hdr_size)
Joel Kingaa335dc2013-06-03 16:11:08 -07001254{
1255 int dt_entry_size;
Channagoud Kadabid87c2772014-06-20 15:41:55 -07001256 uint64_t hdr_size;
Joel Kingaa335dc2013-06-03 16:11:08 -07001257
1258 /* Validate the device tree table header */
1259 if(table->magic != DEV_TREE_MAGIC) {
1260 dprintf(CRITICAL, "ERROR: Bad magic in device tree table \n");
1261 return -1;
1262 }
1263
1264 if (table->version == DEV_TREE_VERSION_V1) {
1265 dt_entry_size = sizeof(struct dt_entry_v1);
1266 } else if (table->version == DEV_TREE_VERSION_V2) {
Lijuan Gao9f152862014-08-18 13:45:24 +08001267 dt_entry_size = sizeof(struct dt_entry_v2);
1268 } else if (table->version == DEV_TREE_VERSION_V3) {
Joel Kingaa335dc2013-06-03 16:11:08 -07001269 dt_entry_size = sizeof(struct dt_entry);
1270 } else {
1271 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
1272 table->version);
1273 return -1;
1274 }
1275
Channagoud Kadabid87c2772014-06-20 15:41:55 -07001276 hdr_size = (uint64_t)table->num_entries * dt_entry_size + DEV_TREE_HEADER_SIZE;
1277
Deepa Dinamani87252952013-09-09 13:58:27 -07001278 /* Roundup to page_size. */
1279 hdr_size = ROUNDUP(hdr_size, page_size);
1280
Channagoud Kadabid87c2772014-06-20 15:41:55 -07001281 if (hdr_size > UINT_MAX)
1282 return -1;
1283 else
1284 *dt_hdr_size = hdr_size & UINT_MAX;
Joel Kingaa335dc2013-06-03 16:11:08 -07001285
1286 return 0;
1287}
1288
Lijuan Gao9f152862014-08-18 13:45:24 +08001289static int platform_dt_absolute_match(struct dt_entry *cur_dt_entry, struct dt_entry_node *dt_list)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001290{
Lijuan Gaof8e95722014-12-23 03:03:12 -05001291 uint32_t cur_dt_hlos_ddr;
Lijuan Gao9f152862014-08-18 13:45:24 +08001292 uint32_t cur_dt_hw_platform;
1293 uint32_t cur_dt_hw_subtype;
1294 uint32_t cur_dt_msm_id;
1295 dt_node *dt_node_tmp = NULL;
Channagoud Kadabi571193a2014-02-05 13:58:49 -08001296
Lijuan Gao9f152862014-08-18 13:45:24 +08001297 /* Platform-id
1298 * bit no |31 24|23 16|15 0|
1299 * |reserved|foundry-id|msm-id|
1300 */
1301 cur_dt_msm_id = (cur_dt_entry->platform_id & 0x0000ffff);
1302 cur_dt_hw_platform = (cur_dt_entry->variant_id & 0x000000ff);
Lijuan Gao0621b862014-09-02 10:02:52 +08001303 cur_dt_hw_subtype = (cur_dt_entry->board_hw_subtype & 0xff);
Lijuan Gao9f152862014-08-18 13:45:24 +08001304
Lijuan Gaof8e95722014-12-23 03:03:12 -05001305 /* Determine the bits 10:8 to check the DT with the DDR Size */
1306 cur_dt_hlos_ddr = (cur_dt_entry->board_hw_subtype & 0x700);
Channagoud Kadabi571193a2014-02-05 13:58:49 -08001307
Lijuan Gao9f152862014-08-18 13:45:24 +08001308 /* 1. must match the msm_id, platform_hw_id, platform_subtype and DDR size
1309 * soc, board major/minor, pmic major/minor must less than board info
1310 * 2. find the matched DTB then return 1
1311 * 3. otherwise return 0
Maria Yu2e2d2c22013-07-03 19:20:33 +08001312 */
Lijuan Gao9f152862014-08-18 13:45:24 +08001313 if((cur_dt_msm_id == (board_platform_id() & 0x0000ffff)) &&
1314 (cur_dt_hw_platform == board_hardware_id()) &&
1315 (cur_dt_hw_subtype == board_hardware_subtype()) &&
Lijuan Gaof8e95722014-12-23 03:03:12 -05001316 (cur_dt_hlos_ddr == (target_get_hlos_subtype() & 0x700)) &&
Lijuan Gao9f152862014-08-18 13:45:24 +08001317 (cur_dt_entry->soc_rev <= board_soc_version()) &&
1318 ((cur_dt_entry->variant_id & 0x00ffff00) <= (board_target_id() & 0x00ffff00)) &&
1319 ((cur_dt_entry->pmic_rev[0] & 0x00ffff00) <= (board_pmic_target(0) & 0x00ffff00)) &&
1320 ((cur_dt_entry->pmic_rev[1] & 0x00ffff00) <= (board_pmic_target(1) & 0x00ffff00)) &&
1321 ((cur_dt_entry->pmic_rev[2] & 0x00ffff00) <= (board_pmic_target(2) & 0x00ffff00)) &&
1322 ((cur_dt_entry->pmic_rev[3] & 0x00ffff00) <= (board_pmic_target(3) & 0x00ffff00))) {
Maria Yu2e2d2c22013-07-03 19:20:33 +08001323
Lijuan Gao9f152862014-08-18 13:45:24 +08001324 dt_node_tmp = dt_entry_list_init();
1325 memcpy((char*)dt_node_tmp->dt_entry_m,(char*)cur_dt_entry, sizeof(struct dt_entry));
1326
1327 dprintf(SPEW, "Add DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1328 dt_node_tmp->dt_entry_m->platform_id, dt_node_tmp->dt_entry_m->variant_id,
1329 dt_node_tmp->dt_entry_m->board_hw_subtype, dt_node_tmp->dt_entry_m->soc_rev,
1330 dt_node_tmp->dt_entry_m->pmic_rev[0], dt_node_tmp->dt_entry_m->pmic_rev[1],
1331 dt_node_tmp->dt_entry_m->pmic_rev[2], dt_node_tmp->dt_entry_m->pmic_rev[3],
1332 dt_node_tmp->dt_entry_m->offset, dt_node_tmp->dt_entry_m->size);
1333
1334 insert_dt_entry_in_queue(dt_list, dt_node_tmp);
1335 return 1;
1336 }
1337 return 0;
1338}
1339
1340static int platform_dt_absolute_compat_match(struct dt_entry_node *dt_list, uint32_t dtb_info) {
1341 struct dt_entry_node *dt_node_tmp1 = NULL;
1342 struct dt_entry_node *dt_node_tmp2 = NULL;
1343 uint32_t current_info = 0;
1344 uint32_t board_info = 0;
1345 uint32_t best_info = 0;
1346 uint32_t current_pmic_model[4] = {0, 0, 0, 0};
1347 uint32_t board_pmic_model[4] = {0, 0, 0, 0};
1348 uint32_t best_pmic_model[4] = {0, 0, 0, 0};
1349 uint32_t delete_current_dt = 0;
1350 uint32_t i;
1351
1352 /* start to select the exact entry
1353 * default to exact match 0, if find current DTB entry info is the same as board info,
1354 * then exact match board info.
1355 */
1356 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1357 if (!dt_node_tmp1){
1358 dprintf(SPEW, "Current node is the end\n");
1359 break;
1360 }
1361 switch(dtb_info) {
1362 case DTB_FOUNDRY:
1363 current_info = ((dt_node_tmp1->dt_entry_m->platform_id) & 0x00ff0000);
Channagoud Kadabi4cffc272014-10-29 11:23:26 -07001364 board_info = board_foundry_id() << 16;
Lijuan Gao9f152862014-08-18 13:45:24 +08001365 break;
1366 case DTB_PMIC_MODEL:
1367 for (i = 0; i < 4; i++) {
1368 current_pmic_model[i] = (dt_node_tmp1->dt_entry_m->pmic_rev[i] & 0xff);
1369 board_pmic_model[i] = (board_pmic_target(i) & 0xff);
1370 }
1371 break;
Lijuan Gaof8e95722014-12-23 03:03:12 -05001372 case DTB_PANEL_TYPE:
1373 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0x1800);
1374 board_info = (target_get_hlos_subtype() & 0x1800);
1375 break;
1376 case DTB_BOOT_DEVICE:
1377 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0xf0000);
1378 board_info = (target_get_hlos_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);
Maria Yuca51ee22013-06-27 21:45:24 +08001383 return 0;
Lijuan Gao9f152862014-08-18 13:45:24 +08001384 }
1385
1386 if (dtb_info == DTB_PMIC_MODEL) {
1387 if ((current_pmic_model[0] == board_pmic_model[0]) &&
1388 (current_pmic_model[1] == board_pmic_model[1]) &&
1389 (current_pmic_model[2] == board_pmic_model[2]) &&
1390 (current_pmic_model[3] == board_pmic_model[3])) {
1391
1392 for (i = 0; i < 4; i++) {
1393 best_pmic_model[i] = current_pmic_model[i];
1394 }
1395 break;
1396 }
1397 } else {
1398 if (current_info == board_info) {
1399 best_info = current_info;
1400 break;
1401 }
1402 }
1403 }
1404
1405 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1406 if (!dt_node_tmp1){
1407 dprintf(SPEW, "Current node is the end\n");
1408 break;
1409 }
1410 switch(dtb_info) {
1411 case DTB_FOUNDRY:
1412 current_info = ((dt_node_tmp1->dt_entry_m->platform_id) & 0x00ff0000);
1413 break;
1414 case DTB_PMIC_MODEL:
1415 for (i = 0; i < 4; i++) {
1416 current_pmic_model[i] = (dt_node_tmp1->dt_entry_m->pmic_rev[i] & 0xff);
1417 }
1418 break;
Lijuan Gaof8e95722014-12-23 03:03:12 -05001419 case DTB_PANEL_TYPE:
1420 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0x1800);
1421 break;
1422 case DTB_BOOT_DEVICE:
1423 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0xf0000);
1424 break;
Lijuan Gao9f152862014-08-18 13:45:24 +08001425 default:
1426 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
1427 dtb_info);
1428 return 0;
1429 }
1430
1431 if (dtb_info == DTB_PMIC_MODEL) {
1432 if ((current_pmic_model[0] != best_pmic_model[0]) ||
1433 (current_pmic_model[1] != best_pmic_model[1]) ||
1434 (current_pmic_model[2] != best_pmic_model[2]) ||
1435 (current_pmic_model[3] != best_pmic_model[3])) {
1436
1437 delete_current_dt = 1;
1438 }
1439 } else {
1440 if (current_info != best_info) {
1441 delete_current_dt = 1;
1442 }
1443 }
1444
1445 if (delete_current_dt) {
1446 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1447 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
1448 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
1449 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
1450 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
1451 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
1452
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001453 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001454 dt_entry_list_delete(dt_node_tmp1);
1455 dt_node_tmp1 = dt_node_tmp2;
1456 delete_current_dt = 0;
Maria Yuca51ee22013-06-27 21:45:24 +08001457 }
1458 }
Maria Yuca51ee22013-06-27 21:45:24 +08001459
Maria Yu2e2d2c22013-07-03 19:20:33 +08001460 return 1;
Maria Yuca51ee22013-06-27 21:45:24 +08001461}
1462
Lijuan Gao9f152862014-08-18 13:45:24 +08001463static int update_dtb_entry_node(struct dt_entry_node *dt_list, uint32_t dtb_info) {
1464 struct dt_entry_node *dt_node_tmp1 = NULL;
1465 struct dt_entry_node *dt_node_tmp2 = NULL;
1466 uint32_t current_info = 0;
1467 uint32_t board_info = 0;
1468 uint32_t best_info = 0;
1469
1470 /* start to select the best entry*/
1471 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1472 if (!dt_node_tmp1){
1473 dprintf(SPEW, "Current node is the end\n");
1474 break;
1475 }
1476 switch(dtb_info) {
1477 case DTB_SOC:
1478 current_info = dt_node_tmp1->dt_entry_m->soc_rev;
1479 board_info = board_soc_version();
1480 break;
1481 case DTB_MAJOR_MINOR:
1482 current_info = ((dt_node_tmp1->dt_entry_m->variant_id) & 0x00ffff00);
1483 board_info = (board_target_id() & 0x00ffff00);
1484 break;
1485 case DTB_PMIC0:
1486 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[0]) & 0x00ffff00);
1487 board_info = (board_pmic_target(0) & 0x00ffff00);
1488 break;
1489 case DTB_PMIC1:
1490 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[1]) & 0x00ffff00);
1491 board_info = (board_pmic_target(1) & 0x00ffff00);
1492 break;
1493 case DTB_PMIC2:
1494 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[2]) & 0x00ffff00);
1495 board_info = (board_pmic_target(2) & 0x00ffff00);
1496 break;
1497 case DTB_PMIC3:
1498 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[3]) & 0x00ffff00);
1499 board_info = (board_pmic_target(3) & 0x00ffff00);
1500 break;
1501 default:
1502 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
1503 dtb_info);
1504 return 0;
1505 }
1506
1507 if (current_info == board_info) {
1508 best_info = current_info;
1509 break;
1510 }
1511 if ((current_info < board_info) && (current_info > best_info)) {
1512 best_info = current_info;
1513 }
1514 if (current_info < best_info) {
1515 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1516 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
1517 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
1518 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
1519 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
1520 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
1521
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001522 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001523 dt_entry_list_delete(dt_node_tmp1);
1524 dt_node_tmp1 = dt_node_tmp2;
1525 }
1526 }
1527
1528 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1529 if (!dt_node_tmp1){
1530 dprintf(SPEW, "Current node is the end\n");
1531 break;
1532 }
1533 switch(dtb_info) {
1534 case DTB_SOC:
1535 current_info = dt_node_tmp1->dt_entry_m->soc_rev;
1536 break;
1537 case DTB_MAJOR_MINOR:
1538 current_info = ((dt_node_tmp1->dt_entry_m->variant_id) & 0x00ffff00);
1539 break;
1540 case DTB_PMIC0:
1541 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[0]) & 0x00ffff00);
1542 break;
1543 case DTB_PMIC1:
1544 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[1]) & 0x00ffff00);
1545 break;
1546 case DTB_PMIC2:
1547 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[2]) & 0x00ffff00);
1548 break;
1549 case DTB_PMIC3:
1550 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[3]) & 0x00ffff00);
1551 break;
1552 default:
1553 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
1554 dtb_info);
1555 return 0;
1556 }
1557
1558 if (current_info != best_info) {
1559 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1560 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
1561 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
1562 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
1563 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
1564 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
1565
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001566 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001567 dt_entry_list_delete(dt_node_tmp1);
1568 dt_node_tmp1 = dt_node_tmp2;
1569 }
1570 }
1571 return 1;
1572}
1573
1574static struct dt_entry *platform_dt_match_best(struct dt_entry_node *dt_list)
1575{
1576 struct dt_entry_node *dt_node_tmp1 = NULL;
1577
1578 /* check Foundry id
1579 * the foundry id must exact match board founddry id, this is compatibility check,
1580 * if couldn't find the exact match from DTB, will exact match 0x0.
1581 */
1582 if (!platform_dt_absolute_compat_match(dt_list, DTB_FOUNDRY))
1583 return NULL;
1584
1585 /* check PMIC model
1586 * the PMIC model must exact match board PMIC model, this is compatibility check,
1587 * if couldn't find the exact match from DTB, will exact match 0x0.
1588 */
1589 if (!platform_dt_absolute_compat_match(dt_list, DTB_PMIC_MODEL))
1590 return NULL;
1591
Lijuan Gaof8e95722014-12-23 03:03:12 -05001592 /* check panel type
1593 * the panel type must exact match board panel type, this is compatibility check,
1594 * if couldn't find the exact match from DTB, will exact match 0x0.
1595 */
1596 if (!platform_dt_absolute_compat_match(dt_list, DTB_PANEL_TYPE))
1597 return NULL;
1598
1599 /* check boot device subtype
1600 * the boot device subtype must exact match board boot device subtype, this is compatibility check,
1601 * if couldn't find the exact match from DTB, will exact match 0x0.
1602 */
1603 if (!platform_dt_absolute_compat_match(dt_list, DTB_BOOT_DEVICE))
1604 return NULL;
1605
Lijuan Gao9f152862014-08-18 13:45:24 +08001606 /* check soc version
1607 * the suitable soc version must less than or equal to board soc version
1608 */
1609 if (!update_dtb_entry_node(dt_list, DTB_SOC))
1610 return NULL;
1611
1612 /*check major and minor version
1613 * the suitable major&minor version must less than or equal to board major&minor version
1614 */
1615 if (!update_dtb_entry_node(dt_list, DTB_MAJOR_MINOR))
1616 return NULL;
1617
1618 /*check pmic info
1619 * the suitable pmic major&minor info must less than or equal to board pmic major&minor version
1620 */
1621 if (!update_dtb_entry_node(dt_list, DTB_PMIC0))
1622 return NULL;
1623 if (!update_dtb_entry_node(dt_list, DTB_PMIC1))
1624 return NULL;
1625 if (!update_dtb_entry_node(dt_list, DTB_PMIC2))
1626 return NULL;
1627 if (!update_dtb_entry_node(dt_list, DTB_PMIC3))
1628 return NULL;
1629
1630 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1631 if (!dt_node_tmp1) {
1632 dprintf(CRITICAL, "ERROR: Couldn't find the suitable DTB!\n");
1633 return NULL;
1634 }
1635 if (dt_node_tmp1->dt_entry_m)
1636 return dt_node_tmp1->dt_entry_m;
1637 }
1638
1639 return NULL;
1640}
1641
1642/* Function to obtain the index information for the correct device tree
1643 * based on the platform data.
1644 * If a matching device tree is found, the information is returned in the
1645 * "dt_entry_info" out parameter and a function value of 0 is returned, otherwise
1646 * a non-zero function value is returned.
1647 */
1648int dev_tree_get_entry_info(struct dt_table *table, struct dt_entry *dt_entry_info)
Maria Yuca51ee22013-06-27 21:45:24 +08001649{
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001650 uint32_t i;
Lijuan Gao9f152862014-08-18 13:45:24 +08001651 unsigned char *table_ptr = NULL;
Joel Kingaa335dc2013-06-03 16:11:08 -07001652 struct dt_entry dt_entry_buf_1;
Lijuan Gao9f152862014-08-18 13:45:24 +08001653 struct dt_entry *cur_dt_entry = NULL;
1654 struct dt_entry *best_match_dt_entry = NULL;
1655 struct dt_entry_v1 *dt_entry_v1 = NULL;
1656 struct dt_entry_v2 *dt_entry_v2 = NULL;
1657 struct dt_entry_node *dt_entry_queue = NULL;
1658 struct dt_entry_node *dt_node_tmp1 = NULL;
1659 struct dt_entry_node *dt_node_tmp2 = NULL;
Maria Yu2e2d2c22013-07-03 19:20:33 +08001660 uint32_t found = 0;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001661
Joel Kingaa335dc2013-06-03 16:11:08 -07001662 if (!dt_entry_info) {
1663 dprintf(CRITICAL, "ERROR: Bad parameter passed to %s \n",
1664 __func__);
1665 return -1;
1666 }
1667
1668 table_ptr = (unsigned char *)table + DEV_TREE_HEADER_SIZE;
1669 cur_dt_entry = &dt_entry_buf_1;
1670 best_match_dt_entry = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +08001671 dt_entry_queue = (struct dt_entry_node *)
1672 malloc(sizeof(struct dt_entry_node));
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001673
Lijuan Gao9f152862014-08-18 13:45:24 +08001674 if (!dt_entry_queue) {
1675 dprintf(CRITICAL, "Out of memory\n");
1676 return -1;
1677 }
1678
1679 list_initialize(&dt_entry_queue->node);
1680 dprintf(INFO, "DTB Total entry: %d, DTB version: %d\n", table->num_entries, table->version);
Maria Yu2e2d2c22013-07-03 19:20:33 +08001681 for(i = 0; found == 0 && i < table->num_entries; i++)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001682 {
Joel Kingaa335dc2013-06-03 16:11:08 -07001683 memset(cur_dt_entry, 0, sizeof(struct dt_entry));
1684 switch(table->version) {
1685 case DEV_TREE_VERSION_V1:
1686 dt_entry_v1 = (struct dt_entry_v1 *)table_ptr;
1687 cur_dt_entry->platform_id = dt_entry_v1->platform_id;
1688 cur_dt_entry->variant_id = dt_entry_v1->variant_id;
1689 cur_dt_entry->soc_rev = dt_entry_v1->soc_rev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001690 cur_dt_entry->board_hw_subtype = (dt_entry_v1->variant_id >> 0x18);
1691 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
1692 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
1693 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
1694 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
Joel Kingaa335dc2013-06-03 16:11:08 -07001695 cur_dt_entry->offset = dt_entry_v1->offset;
1696 cur_dt_entry->size = dt_entry_v1->size;
1697 table_ptr += sizeof(struct dt_entry_v1);
1698 break;
1699 case DEV_TREE_VERSION_V2:
Lijuan Gao9f152862014-08-18 13:45:24 +08001700 dt_entry_v2 = (struct dt_entry_v2*)table_ptr;
1701 cur_dt_entry->platform_id = dt_entry_v2->platform_id;
1702 cur_dt_entry->variant_id = dt_entry_v2->variant_id;
1703 cur_dt_entry->soc_rev = dt_entry_v2->soc_rev;
1704 /* For V2 version of DTBs we have platform version field as part
1705 * of variant ID, in such case the subtype will be mentioned as 0x0
1706 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
1707 * SS -- Subtype
1708 * PM -- Platform major version
1709 * Pm -- Platform minor version
1710 * PH -- Platform hardware CDP/MTP
1711 * In such case to make it compatible with LK algorithm move the subtype
1712 * from variant_id to subtype field
1713 */
1714 if (dt_entry_v2->board_hw_subtype == 0)
1715 cur_dt_entry->board_hw_subtype = (cur_dt_entry->variant_id >> 0x18);
1716 else
1717 cur_dt_entry->board_hw_subtype = dt_entry_v2->board_hw_subtype;
1718 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
1719 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
1720 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
1721 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
1722 cur_dt_entry->offset = dt_entry_v2->offset;
1723 cur_dt_entry->size = dt_entry_v2->size;
1724 table_ptr += sizeof(struct dt_entry_v2);
1725 break;
1726 case DEV_TREE_VERSION_V3:
Joel Kingaa335dc2013-06-03 16:11:08 -07001727 memcpy(cur_dt_entry, (struct dt_entry *)table_ptr,
1728 sizeof(struct dt_entry));
Lijuan Gao9f152862014-08-18 13:45:24 +08001729 /* For V3 version of DTBs we have platform version field as part
1730 * of variant ID, in such case the subtype will be mentioned as 0x0
1731 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
1732 * SS -- Subtype
1733 * PM -- Platform major version
1734 * Pm -- Platform minor version
1735 * PH -- Platform hardware CDP/MTP
1736 * In such case to make it compatible with LK algorithm move the subtype
1737 * from variant_id to subtype field
1738 */
1739 if (cur_dt_entry->board_hw_subtype == 0)
1740 cur_dt_entry->board_hw_subtype = (cur_dt_entry->variant_id >> 0x18);
1741
Joel Kingaa335dc2013-06-03 16:11:08 -07001742 table_ptr += sizeof(struct dt_entry);
1743 break;
1744 default:
1745 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
1746 table->version);
Lijuan Gao9f152862014-08-18 13:45:24 +08001747 free(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001748 return -1;
1749 }
1750
Lijuan Gao9f152862014-08-18 13:45:24 +08001751 /* DTBs must match the platform_id, platform_hw_id, platform_subtype and DDR size.
1752 * The satisfactory DTBs are stored in dt_entry_queue
1753 */
1754 platform_dt_absolute_match(cur_dt_entry, dt_entry_queue);
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -08001755
Lijuan Gao9f152862014-08-18 13:45:24 +08001756 }
1757 best_match_dt_entry = platform_dt_match_best(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001758 if (best_match_dt_entry) {
1759 *dt_entry_info = *best_match_dt_entry;
Maria Yu2e2d2c22013-07-03 19:20:33 +08001760 found = 1;
1761 }
1762
1763 if (found != 0) {
Sundarajan Srinivasan763c0db2014-05-20 17:08:36 -07001764 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 -07001765 dt_entry_info->platform_id, dt_entry_info->soc_rev,
1766 dt_entry_info->variant_id, dt_entry_info->board_hw_subtype,
Lijuan Gao9f152862014-08-18 13:45:24 +08001767 board_platform_id(), board_soc_version(),
1768 board_target_id(), board_hardware_subtype());
1769 if (dt_entry_info->pmic_rev[0] == 0 && dt_entry_info->pmic_rev[0] == 0 &&
1770 dt_entry_info->pmic_rev[0] == 0 && dt_entry_info->pmic_rev[0] == 0) {
1771 dprintf(SPEW, "No maintain pmic info in DTB, device pmic info is 0x%0x/0x%x/0x%x/0x%0x\n",
1772 board_pmic_target(0), board_pmic_target(1),
1773 board_pmic_target(2), board_pmic_target(3));
1774 } else {
1775 dprintf(INFO, "Using pmic info 0x%0x/0x%x/0x%x/0x%0x for device 0x%0x/0x%x/0x%x/0x%0x\n",
1776 dt_entry_info->pmic_rev[0], dt_entry_info->pmic_rev[1],
1777 dt_entry_info->pmic_rev[2], dt_entry_info->pmic_rev[3],
1778 board_pmic_target(0), board_pmic_target(1),
1779 board_pmic_target(2), board_pmic_target(3));
1780 }
Joel Kingaa335dc2013-06-03 16:11:08 -07001781 return 0;
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -08001782 }
1783
Lijuan Gao9f152862014-08-18 13:45:24 +08001784 dprintf(CRITICAL, "ERROR: Unable to find suitable device tree for device (%u/0x%08x/0x%08x/%u)\n",
1785 board_platform_id(), board_soc_version(),
1786 board_target_id(), board_hardware_subtype());
1787
1788 list_for_every_entry(&dt_entry_queue->node, dt_node_tmp1, dt_node, node) {
1789 /* free node memory */
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001790 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001791 dt_entry_list_delete(dt_node_tmp1);
1792 dt_node_tmp1 = dt_node_tmp2;
1793 }
1794 free(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001795 return -1;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001796}
1797
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001798/* Function to add the first RAM partition info to the device tree.
1799 * Note: The function replaces the reg property in the "/memory" node
1800 * with the addr and size provided.
1801 */
1802int dev_tree_add_first_mem_info(uint32_t *fdt, uint32_t offset, uint32_t addr, uint32_t size)
1803{
1804 int ret;
1805
1806 ret = fdt_setprop_u32(fdt, offset, "reg", addr);
1807
1808 if (ret)
1809 {
1810 dprintf(CRITICAL, "Failed to add the memory information addr: %d\n",
1811 ret);
1812 }
1813
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001814 ret = fdt_appendprop_u32(fdt, offset, "reg", size);
1815
1816 if (ret)
1817 {
1818 dprintf(CRITICAL, "Failed to add the memory information size: %d\n",
1819 ret);
1820 }
1821
1822 return ret;
1823}
1824
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001825static 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 -07001826{
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001827 int len;
1828 uint32_t *valp;
1829 int ret;
1830 uint32_t offset;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001831
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001832 mem_node->offset = mem_node_offset;
1833
1834 /* Get offset of the root node */
1835 ret = fdt_path_offset(fdt, "/");
1836 if (ret < 0)
1837 {
1838 dprintf(CRITICAL, "Could not find memory node.\n");
1839 return ret;
1840 }
1841
1842 offset = ret;
1843
1844 /* Find the #address-cells size. */
1845 valp = (uint32_t*)fdt_getprop(fdt, offset, "#address-cells", &len);
Lijuan Gaoae0927b2014-07-18 17:16:16 +08001846 if (len <= 0 || !valp)
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001847 {
1848 if (len == -FDT_ERR_NOTFOUND)
1849 {
1850 /* Property not found.
1851 * Assume standard sizes.
1852 */
1853 mem_node->addr_cell_size = 2;
1854 dprintf(CRITICAL, "Using default #addr_cell_size: %u\n", mem_node->addr_cell_size);
1855 }
1856 else
1857 {
1858 dprintf(CRITICAL, "Error finding the #address-cells property\n");
1859 return len;
1860 }
1861 }
1862 else
1863 mem_node->addr_cell_size = fdt32_to_cpu(*valp);
1864
1865 /* Find the #size-cells size. */
1866 valp = (uint32_t*)fdt_getprop(fdt, offset, "#size-cells", &len);
Lijuan Gaoae0927b2014-07-18 17:16:16 +08001867 if (len <= 0 || !valp)
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001868 {
1869 if (len == -FDT_ERR_NOTFOUND)
1870 {
1871 /* Property not found.
1872 * Assume standard sizes.
1873 */
1874 mem_node->size_cell_size = 1;
1875 dprintf(CRITICAL, "Using default #size_cell_size: %u\n", mem_node->size_cell_size);
1876 }
1877 else
1878 {
1879 dprintf(CRITICAL, "Error finding the #size-cells property\n");
1880 return len;
1881 }
1882 }
1883 else
1884 mem_node->size_cell_size = fdt32_to_cpu(*valp);
1885
1886 return 0;
1887}
1888
1889static void dev_tree_update_memory_node(uint32_t offset)
1890{
1891 mem_node.offset = offset;
1892 mem_node.addr_cell_size = 1;
1893 mem_node.size_cell_size = 1;
1894}
1895
1896/* Function to add the subsequent RAM partition info to the device tree. */
1897int dev_tree_add_mem_info(void *fdt, uint32_t offset, uint64_t addr, uint64_t size)
1898{
1899 int ret = 0;
1900
1901 if(smem_get_ram_ptable_version() >= 1)
1902 {
1903 ret = dev_tree_query_memory_cell_sizes(fdt, &mem_node, offset);
1904 if (ret < 0)
1905 {
1906 dprintf(CRITICAL, "Could not find #address-cells and #size-cells properties: ret %d\n", ret);
1907 return ret;
1908 }
1909
1910 }
1911 else
1912 {
1913 dev_tree_update_memory_node(offset);
1914 }
1915
1916 if (!(mem_node.mem_info_cnt))
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001917 {
1918 /* Replace any other reg prop in the memory node. */
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001919
1920 /* cell_size is the number of 32 bit words used to represent an address/length in the device tree.
1921 * memory node in DT can be either 32-bit(cell-size = 1) or 64-bit(cell-size = 2).So when updating
1922 * the memory node in the device tree, we write one word or two words based on cell_size = 1 or 2.
1923 */
1924
1925 if(mem_node.addr_cell_size == 2)
1926 {
1927 ret = fdt_setprop_u32(fdt, mem_node.offset, "reg", addr >> 32);
1928 if(ret)
1929 {
1930 dprintf(CRITICAL, "ERROR: Could not set prop reg for memory node\n");
1931 return ret;
1932 }
1933
1934 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1935 if(ret)
1936 {
1937 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1938 return ret;
1939 }
1940 }
1941 else
1942 {
1943 ret = fdt_setprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1944 if(ret)
1945 {
1946 dprintf(CRITICAL, "ERROR: Could not set prop reg for memory node\n");
1947 return ret;
1948 }
1949 }
1950
1951 mem_node.mem_info_cnt = 1;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001952 }
1953 else
1954 {
1955 /* Append the mem info to the reg prop for subsequent nodes. */
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001956 if(mem_node.addr_cell_size == 2)
1957 {
1958 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", addr >> 32);
1959 if(ret)
1960 {
1961 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1962 return ret;
1963 }
1964 }
1965
1966 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1967 if(ret)
1968 {
1969 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1970 return ret;
1971 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001972 }
1973
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001974 if(mem_node.size_cell_size == 2)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001975 {
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001976 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", size>>32);
1977 if(ret)
1978 {
1979 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1980 return ret;
1981 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001982 }
1983
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001984 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)size);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001985
1986 if (ret)
1987 {
1988 dprintf(CRITICAL, "Failed to add the memory information size: %d\n",
1989 ret);
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001990 return ret;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001991 }
1992
1993 return ret;
1994}
1995
1996/* Top level function that updates the device tree. */
1997int update_device_tree(void *fdt, const char *cmdline,
1998 void *ramdisk, uint32_t ramdisk_size)
1999{
2000 int ret = 0;
2001 uint32_t offset;
lijuangc76a7632017-12-07 14:37:56 +08002002#if ENABLE_KASLRSEED_SUPPORT
2003 uintptr_t kaslrseed;
2004#endif
Mayank Grover2533aab2018-02-23 18:06:07 +05302005 uint32_t cmdline_len = 0;
2006
2007 if (cmdline)
2008 cmdline_len = strlen(cmdline);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002009
2010 /* Check the device tree header */
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +05302011 ret = fdt_check_header(fdt) || fdt_check_header_ext(fdt);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002012 if (ret)
2013 {
2014 dprintf(CRITICAL, "Invalid device tree header \n");
2015 return ret;
2016 }
2017
P.V. Phani Kumar9cd95102016-03-09 12:35:23 +05302018 if (check_aboot_addr_range_overlap((uint32_t)fdt,
Mayank Grover2533aab2018-02-23 18:06:07 +05302019 (fdt_totalsize(fdt) + DTB_PAD_SIZE + cmdline_len))) {
P.V. Phani Kumar9cd95102016-03-09 12:35:23 +05302020 dprintf(CRITICAL, "Error: Fdt addresses overlap with aboot addresses.\n");
2021 return ret;
2022 }
2023
Deepa Dinamani1c970732013-04-19 14:23:01 -07002024 /* Add padding to make space for new nodes and properties. */
Mayank Grover2533aab2018-02-23 18:06:07 +05302025 ret = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + DTB_PAD_SIZE + cmdline_len);
Deepa Dinamani1c970732013-04-19 14:23:01 -07002026 if (ret!= 0)
2027 {
2028 dprintf(CRITICAL, "Failed to move/resize dtb buffer: %d\n", ret);
2029 return ret;
2030 }
2031
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002032 /* Get offset of the memory node */
2033 ret = fdt_path_offset(fdt, "/memory");
2034 if (ret < 0)
2035 {
2036 dprintf(CRITICAL, "Could not find memory node.\n");
2037 return ret;
2038 }
2039
2040 offset = ret;
2041
2042 ret = target_dev_tree_mem(fdt, offset);
2043 if(ret)
2044 {
2045 dprintf(CRITICAL, "ERROR: Cannot update memory node\n");
2046 return ret;
2047 }
2048
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002049 /* Get offset of the chosen node */
2050 ret = fdt_path_offset(fdt, "/chosen");
2051 if (ret < 0)
2052 {
2053 dprintf(CRITICAL, "Could not find chosen node.\n");
2054 return ret;
2055 }
2056
2057 offset = ret;
Maria Yuabde9542014-07-07 14:49:34 +08002058 if (cmdline)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002059 {
Maria Yuabde9542014-07-07 14:49:34 +08002060 /* Adding the cmdline to the chosen node */
2061 ret = fdt_appendprop_string(fdt, offset, (const char*)"bootargs", (const void*)cmdline);
2062 if (ret)
2063 {
2064 dprintf(CRITICAL, "ERROR: Cannot update chosen node [bootargs]\n");
2065 return ret;
2066 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002067 }
2068
lijuangc76a7632017-12-07 14:37:56 +08002069#if ENABLE_KASLRSEED_SUPPORT
2070 if (!scm_random(&kaslrseed, sizeof(kaslrseed))) {
2071 /* Adding Kaslr Seed to the chosen node */
2072 ret = fdt_appendprop_u64 (fdt, offset, (const char *)"kaslr-seed", (uint64_t)kaslrseed);
2073 if (ret)
2074 dprintf(CRITICAL, "ERROR: Cannot update chosen node [kaslr-seed] - 0x%x\n", ret);
2075 else
2076 dprintf(CRITICAL, "kaslr-Seed is added to chosen node\n");
2077 } else {
2078 dprintf(CRITICAL, "ERROR: Cannot generate Kaslr Seed\n");
2079 }
2080#endif
2081
Joonwoo Parka5b5f492014-02-13 18:24:48 -08002082 if (ramdisk_size) {
2083 /* Adding the initrd-start to the chosen node */
2084 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-start",
2085 (uint32_t)ramdisk);
2086 if (ret)
2087 {
2088 dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-start]\n");
2089 return ret;
2090 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002091
Joonwoo Parka5b5f492014-02-13 18:24:48 -08002092 /* Adding the initrd-end to the chosen node */
2093 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-end",
2094 ((uint32_t)ramdisk + ramdisk_size));
2095 if (ret)
2096 {
2097 dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-end]\n");
2098 return ret;
2099 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002100 }
2101
Kishor PK536904a2017-07-13 17:18:59 +05302102#if ENABLE_BOOTDEVICE_MOUNT
2103 /* Update fstab node */
2104 dprintf(SPEW, "Start of fstab node update:%zu ms\n", platform_get_sclk_count());
2105 if (update_fstab_node(fdt) != 0) {
2106 dprintf(CRITICAL, "ERROR: Cannot update fstab node\n");
2107 return ret;
2108 }
2109 dprintf(SPEW, "End of fstab node update:%zu ms\n", platform_get_sclk_count());
2110#endif
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002111 fdt_pack(fdt);
2112
Channagoud Kadabiffaea422014-12-05 15:45:41 -08002113#if ENABLE_PARTIAL_GOODS_SUPPORT
2114 update_partial_goods_dtb_nodes(fdt);
2115#endif
2116
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002117 return ret;
2118}
Kishor PK536904a2017-07-13 17:18:59 +05302119
2120#if ENABLE_BOOTDEVICE_MOUNT
2121/*Update device tree for fstab node */
2122static int update_fstab_node(void *fdt)
2123{
2124 int ret = 0;
2125 int str_len = 0;
2126 int parent_offset = 0;
2127 int subnode_offset = 0;
2128 int prop_length = 0;
2129 int prefix_string_len = 0;
2130 char *node_name = NULL;
2131 char *boot_dev_buf = NULL;
2132 char *new_str = NULL;
2133 char *prefix_str = NULL;
2134 char *suffix_str = NULL;
2135 const struct fdt_property *prop = NULL;
2136
2137 /* Find the parent node */
2138 parent_offset = fdt_path_offset(fdt, fstab_table.parent_node);
2139 if (parent_offset < 0) {
2140 dprintf(CRITICAL, "Failed to get parent node: fstab error: %d\n", parent_offset);
2141 return -1;
2142 }
2143 dprintf(SPEW, "Node: %s found.\n", fdt_get_name(fdt, parent_offset, NULL));
2144
2145 /* Get boot device type */
2146 boot_dev_buf = (char *) malloc(sizeof(char) * BOOT_DEV_MAX_LEN);
2147 if (!boot_dev_buf) {
2148 dprintf(CRITICAL, "Failed to allocate memory for boot device\n");
2149 return -1;
2150 }
2151
2152 new_str = (char *) malloc(sizeof(char) * NODE_PROPERTY_MAX_LEN);
2153 if (!new_str) {
2154 dprintf(CRITICAL, "Failed to allocate memory for node property string\n");
2155 return -1;
2156 }
2157
2158
2159 platform_boot_dev_cmdline(boot_dev_buf);
2160
2161 /* Get properties of all sub nodes */
2162 for (subnode_offset = fdt_first_subnode(fdt, parent_offset); subnode_offset >= 0; subnode_offset = fdt_next_subnode(fdt, subnode_offset)) {
2163 prop = fdt_get_property(fdt, subnode_offset, fstab_table.node_prop, &prop_length);
2164 node_name = (char *)(uintptr_t)fdt_get_name(fdt, subnode_offset, NULL);
2165 if (!prop) {
2166 dprintf(CRITICAL, "Property:%s is not found for sub node:%s\n", fstab_table.node_prop, node_name);
2167 } else {
2168 dprintf(CRITICAL, "Property:%s found for sub node:%s\tproperty:%s\n", fstab_table.node_prop, node_name, prop->data);
2169 /* Pointer to fdt 'dev' property string that needs to update based on the 'androidboot.bootdevice' */
2170 memset(new_str, 0, NODE_PROPERTY_MAX_LEN);
2171 prefix_str = (char *)prop->data;
2172 if (strlen(prefix_str) > NODE_PROPERTY_MAX_LEN) {
2173 dprintf(CRITICAL, "Property string length is greater than node property max length\n");
2174 continue;
2175 }
2176 suffix_str = strstr(prefix_str, fstab_table.device_path_id);
2177 if (!suffix_str) {
2178 dprintf(CRITICAL, "Property is not proper to update\n");
2179 continue;
2180 }
2181 suffix_str += strlen(fstab_table.device_path_id);
2182 prefix_string_len = strlen(prefix_str) - (strlen(suffix_str) - 1);
2183 suffix_str = strstr((suffix_str + 1), "/");
2184 str_len = strlcpy(new_str, prefix_str, prefix_string_len);
2185 if (!str_len) {
2186 dprintf(CRITICAL, "Property length is not proper to update\n");
2187 continue;
2188 }
2189 str_len = strlcat(new_str, boot_dev_buf, strlen(prefix_str));
2190 if (!str_len) {
2191 dprintf(CRITICAL, "Property length is not proper to update\n");
2192 continue;
2193 }
2194 str_len = strlcat(new_str, suffix_str, strlen(prefix_str));
2195 if (!str_len) {
2196 dprintf(CRITICAL, "Property length is not proper to update\n");
2197 continue;
2198 }
2199 /* Update the new property in the memory */
2200 memscpy(prefix_str, strlen(prefix_str), new_str, strlen(new_str) + 1);
2201 /* Update the property with new value */
2202 ret = fdt_setprop(fdt, subnode_offset, fstab_table.node_prop, (const void *)prefix_str, strlen(prefix_str) + 1);
2203 if(ret) {
2204 dprintf(CRITICAL, "Failed to update the node with new property\n");
2205 continue;
2206 }
2207 dprintf(CRITICAL, "Updated %s with new property %s\n", node_name, prop->data);
2208 }
2209 }
2210 if (boot_dev_buf)
2211 free(boot_dev_buf);
2212 if (new_str)
2213 free(new_str);
2214 return ret;
2215}
2216#endif