blob: 752a7e912171bdf635230dc26f33ac9bf3f48184 [file] [log] [blame]
Mayank Grover324a9772019-05-08 16:06:19 +05301/* Copyright (c) 2012-2015,2017-2019 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>
Mayank Grover8f46a892018-09-10 13:24:59 +053050#include <verifiedboot.h>
Kishor PK536904a2017-07-13 17:18:59 +053051
Kishor PK536904a2017-07-13 17:18:59 +053052#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 =
Mayank Grover8f46a892018-09-10 13:24:59 +0530248 (void *)ROUND_TO_PAGE((addr_t)dtbo_image_buf, (ADDR_ALIGNMENT-1));
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530249 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
Mayank Grover8f46a892018-09-10 13:24:59 +0530256 /* Add offset for salt buffer for verification */
257 dtbo_image_buf += SALT_BUFF_OFFSET;
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530258 /* Read dtbo partition with header */
259 if (mmc_read(ptn, (uint32_t *)(dtbo_image_buf), dtbo_partition_size))
260 {
261 dprintf(CRITICAL, "ERROR: dtbo partition mmc read failure \n");
262 ret = DTBO_ERROR;
263 goto out;
264 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530265 }
266
267 /* validate the dtbo image, before reading complete image */
268 dtbo_table_header = (struct dtbo_table_hdr *)dtbo_image_buf;
269
270 /*Check for dtbo magic*/
271 if (fdt32_to_cpu(dtbo_table_header->magic) != DTBO_TABLE_MAGIC)
272 {
273 dprintf(CRITICAL, "dtbo header magic mismatch %x, with %x\n",
274 fdt32_to_cpu(dtbo_table_header->magic), DTBO_TABLE_MAGIC);
275 ret = DTBO_ERROR;
276 goto out;
277 }
278
279 /*Check for dtbo image table size*/
280 if (fdt32_to_cpu(dtbo_table_header->hdr_size) != sizeof(struct dtbo_table_hdr))
281 {
282 dprintf(CRITICAL, "dtbo table header size got corrupted\n");
283 ret = DTBO_ERROR;
284 goto out;
285 }
286
287 /*Check for dt entry size of dtbo image*/
288 if (fdt32_to_cpu(dtbo_table_header->dt_entry_size) != sizeof(struct dtbo_table_entry))
289 {
290 dprintf(CRITICAL, "dtbo table dt entry size got corrupted\n");
291 ret = DTBO_ERROR;
292 goto out;
293 }
294
295 /*Total size of dtbo */
296 dtbo_total_size = fdt32_to_cpu(dtbo_table_header->total_size);
297 if (dtbo_total_size > dtbo_partition_size || dtbo_total_size == 0)
298 {
299 dprintf(CRITICAL, "dtbo table total size exceeded the dtbo buffer allocated\n");
300 ret = DTBO_ERROR;
301 goto out;
302 }
303
304 /* Total size of dtbo entries */
305 dtbo_total_size = fdt32_to_cpu(dtbo_table_header->dt_entry_count) *
306 fdt32_to_cpu(dtbo_table_header->dt_entry_size);
307 if (dtbo_total_size > dtbo_partition_size || dtbo_total_size == 0)
308 {
309 dprintf(CRITICAL, "dtbo table total size exceeded the dtbo buffer allocated\n");
310 ret = DTBO_ERROR;
311 goto out;
312 }
313
314 /* Offset should be less than image size */
315 if (fdt32_to_cpu(dtbo_table_header->dt_entry_offset) > dtbo_partition_size)
316 {
317 dprintf(CRITICAL, "dtbo offset exceeds the dtbo buffer allocated\n");
318 ret = DTBO_ERROR;
319 goto out;
320 }
321
322 /* Offset + total size is less than image size */
323 if (dtbo_total_size + fdt32_to_cpu(dtbo_table_header->dt_entry_offset) > dtbo_partition_size)
324 {
325 dprintf(CRITICAL, "dtbo size exceeded the dtbo buffer allocated\n");
326 ret = DTBO_ERROR;
327 }
328
329out:
Mayank Groverb61c0c22018-09-04 15:09:32 +0530330 if (ret == DTBO_SUCCESS)
331 {
332 *dtbo_buf = dtbo_image_buf;
333 *dtbo_image_sz = (uint32_t)ptn_size;
334 dtbo_loaded = true;
335 }
336 else
337 {
338 *dtbo_buf = NULL;
339 *dtbo_image_sz = 0;
340 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530341 return ret;
342}
343
344static bool check_all_bits_set(uint32_t matchdt_value)
345{
346 return (matchdt_value & ALL_BITS_SET) == (ALL_BITS_SET);
347}
348
349/* Dt selection table for quick reference
350 | SNO | Dt Property | CDT Property | Exact | Best | Default |
351 |-----+---------------+-----------------+-------+------+---------+
352 | | qcom, msm-id | | | | |
353 | | | PlatformId | Y | N | N |
354 | | | SocRev | N | Y | N |
355 | | | FoundryId | Y | N | 0 |
356 | | qcom,board-id | | | | |
357 | | | VariantId | Y | N | N |
358 | | | VariantMajor | N | Y | N |
359 | | | VariantMinor | N | Y | N |
360 | | | PlatformSubtype | Y | N | 0 |
361 | | qcom,pmic-id | | | | |
362 | | | PmicModelId | Y | N | 0 |
363 | | | PmicMetalRev | N | Y | N |
364 | | | PmicLayerRev | N | Y | N |
365 | | | PmicVariantRev | N | Y | N |
366*/
367
lijuang0cce8bf2018-08-23 10:56:42 +0800368static 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 +0530369{
370 int board_id_len;
371 int platform_id_len = 0;
372 int pmic_id_len;
373 int root_offset = 0;
374 void *dtb = current_dtb_info->dtb;
375 uint32_t idx;
376 const char *platform_prop = NULL;
377 const char *board_prop = NULL;
378 const char *pmic_prop = NULL;
lijuang0cce8bf2018-08-23 10:56:42 +0800379 boolean find_best_match = false;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530380
381 current_dtb_info->dt_match_val = 0;
382 root_offset = fdt_path_offset(dtb, "/");
383 if (root_offset < 0) {
384 dprintf(CRITICAL, "ERROR: Unable to locate root node\n");
lijuang0cce8bf2018-08-23 10:56:42 +0800385 return false;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530386 }
387
388 /* Get the msm-id prop from DTB and find best match */
389 platform_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,msm-id", &platform_id_len);
390 if (platform_prop && (platform_id_len > 0) && (!(platform_id_len % PLAT_ID_SIZE))) {
391 /*Compare msm-id of the dtb vs board*/
392 current_dtb_info->dt_platform_id = fdt32_to_cpu(((struct plat_id *)platform_prop)->platform_id);
393 dprintf(SPEW, "Board SOC ID = %x | DT SOC ID = %x\n", (board_platform_id() & SOC_MASK),
394 (current_dtb_info->dt_platform_id & SOC_MASK));
395 if ((board_platform_id() & SOC_MASK) == (current_dtb_info->dt_platform_id & SOC_MASK)) {
396 current_dtb_info->dt_match_val |= BIT(SOC_MATCH);
397 } else {
398 dprintf(SPEW, "qcom,msm-id does not match\n");
399 /* If soc doesn't match, don't select dtb */
400 current_dtb_info->dt_match_val = BIT(NONE_MATCH);
401 goto cleanup;
402 }
403 /*Compare soc rev of the dtb vs board*/
404 current_dtb_info->dt_soc_rev = fdt32_to_cpu(((struct plat_id *)platform_prop)->soc_rev);
405 dprintf(SPEW, "Board SOC Rev = %x | DT SOC Rev =%x\n", board_soc_version(),
406 current_dtb_info->dt_soc_rev);
407 if (current_dtb_info->dt_soc_rev == board_soc_version()) {
408 current_dtb_info->dt_match_val |= BIT(VERSION_EXACT_MATCH);
409 } else if (current_dtb_info->dt_soc_rev < board_soc_version()) {
410 current_dtb_info->dt_match_val |= BIT(VERSION_BEST_MATCH);
411 } else if (current_dtb_info->dt_soc_rev) {
412 dprintf(SPEW, "SOC version does not match\n");
413 }
414 /*Compare Foundry Id of the dtb vs Board*/
415 current_dtb_info->dt_foundry_id = fdt32_to_cpu(((struct plat_id *)platform_prop)->platform_id) & FOUNDRY_ID_MASK;
416 dprintf (SPEW, "Board Foundry id = %x | DT Foundry id = %x\n", (board_foundry_id() << PLATFORM_FOUNDRY_SHIFT), current_dtb_info->dt_foundry_id);
417 if (current_dtb_info->dt_foundry_id == (board_foundry_id() << PLATFORM_FOUNDRY_SHIFT)) {
418 current_dtb_info->dt_match_val |= BIT (FOUNDRYID_EXACT_MATCH);
419 } else if (current_dtb_info->dt_foundry_id == 0 ){
420 current_dtb_info->dt_match_val |= BIT (FOUNDRYID_DEFAULT_MATCH);
421 } else {
422 dprintf(SPEW, "soc foundry does not match\n");
423 /* If soc doesn't match, don't select dtb */
424 current_dtb_info->dt_match_val = BIT(NONE_MATCH);
425 goto cleanup;
426 }
427 } else {
428 dprintf(SPEW, "qcom,msm-id does not exist (or) is (%d) not a multiple of (%d)\n", platform_id_len, PLAT_ID_SIZE);
429 }
430
431 /* Get the properties like variant id, subtype from DTB and compare the DTB vs Board */
432 board_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,board-id", &board_id_len);
433 if (board_prop && (board_id_len > 0) && (!(board_id_len % BOARD_ID_SIZE))) {
434 current_dtb_info->dt_variant_id = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id);
435 current_dtb_info->dt_platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->platform_subtype);
436 if (current_dtb_info->dt_platform_subtype == 0)
437 current_dtb_info->dt_platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id) >> PLATFORM_SUBTYPE_SHIFT_ID;
438
439 dprintf(SPEW, "Board variant id = %x | DT variant id = %x\n",board_hardware_id(), current_dtb_info->dt_variant_id);
440
441 current_dtb_info->dt_variant_major = current_dtb_info->dt_variant_id & VARIANT_MAJOR_MASK;
442 current_dtb_info->dt_variant_minor = current_dtb_info->dt_variant_id & VARIANT_MINOR_MASK;
443 current_dtb_info->dt_variant_id = current_dtb_info->dt_variant_id & VARIANT_MASK;
444
445 if (current_dtb_info->dt_variant_id == board_hardware_id()) {
446 current_dtb_info->dt_match_val |= BIT(VARIANT_MATCH);
447 } else if (current_dtb_info->dt_variant_id) {
448 dprintf(SPEW, "qcom,board-id doesnot match\n");
449 /* If board variant doesn't match, don't select dtb */
450 current_dtb_info->dt_match_val = BIT(NONE_MATCH);
451 goto cleanup;
452 }
453
454 if (current_dtb_info->dt_variant_major == (board_target_id() & VARIANT_MAJOR_MASK)) {
455 current_dtb_info->dt_match_val |= BIT(VARIANT_MAJOR_EXACT_MATCH);
456 } else if (current_dtb_info->dt_variant_major < (board_target_id() & VARIANT_MAJOR_MASK)) {
457 current_dtb_info->dt_match_val |= BIT(VARIANT_MAJOR_BEST_MATCH);
458 } else if (current_dtb_info->dt_variant_major) {
459 dprintf(SPEW, "qcom,board-id major version doesnot match\n");
460 }
461
462 if (current_dtb_info->dt_variant_minor == (board_target_id() & VARIANT_MINOR_MASK)) {
463 current_dtb_info->dt_match_val |= BIT(VARIANT_MINOR_EXACT_MATCH);
464 } else if (current_dtb_info->dt_variant_minor < (board_target_id() & VARIANT_MINOR_MASK)) {
465 current_dtb_info->dt_match_val |= BIT(VARIANT_MINOR_BEST_MATCH);
466 } else if (current_dtb_info->dt_variant_minor) {
467 dprintf(SPEW, "qcom,board-id minor version doesnot match\n");
468 }
469
470 dprintf(SPEW, "Board platform subtype = %x | DT platform subtype = %x\n",
471 board_hardware_subtype(), current_dtb_info->dt_platform_subtype);
472 if (current_dtb_info->dt_platform_subtype == board_hardware_subtype()) {
473 current_dtb_info->dt_match_val |= BIT(SUBTYPE_EXACT_MATCH);
474 } else if (current_dtb_info->dt_platform_subtype == 0) {
475 current_dtb_info->dt_match_val |= BIT(SUBTYPE_DEFAULT_MATCH);
476 } else if (current_dtb_info->dt_platform_subtype) {
477 dprintf(SPEW, "subtype id doesnot match\n");
478 /* If board platform doesn't match, don't select dtb */
479 current_dtb_info->dt_match_val = BIT(NONE_MATCH);
480 goto cleanup;
481 }
482 } else {
483 dprintf(SPEW, "qcom,board-id does not exist (or)(%d) is not a multiple of (%d)\n",
484 board_id_len, BOARD_ID_SIZE);
485 }
486
487 /* Get the pmic property from DTB then compare the DTB vs Board */
488 pmic_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,pmic-id", &pmic_id_len);
489 if (pmic_prop && (pmic_id_len > 0) && (!(pmic_id_len % sizeof(struct pmic_id))))
490 {
491 pmic_info curr_pmic_info;
492 pmic_info best_pmic_info;
493 unsigned int pmic_entry_indx;
494 unsigned int pmic_entries_count;
495
496 /* Find all pmic entries count */
497 pmic_entries_count = pmic_id_len/sizeof(struct pmic_id);
498
499 memset(&best_pmic_info, 0, sizeof(pmic_info));
500 for (pmic_entry_indx = 0; pmic_entry_indx < pmic_entries_count; pmic_entry_indx++)
501 {
502 memset(&curr_pmic_info, 0, sizeof(pmic_info));
503
504 /* Read all pmic info */
505 /* Compare with board pmic */
506 for (idx = 0; idx < MAX_PMIC_IDX; idx++)
507 {
508 curr_pmic_info.dt_pmic_model[idx] =
509 fdt32_to_cpu (((struct pmic_id *)pmic_prop)->pmic_version[idx]);
510 dprintf(SPEW, "pmic_data[%u]:%x\n", idx, curr_pmic_info.dt_pmic_model[idx]);
511 curr_pmic_info.dt_pmic_rev[idx] =
512 curr_pmic_info.dt_pmic_model[idx] & PMIC_REV_MASK;
513 curr_pmic_info.dt_pmic_model[idx] =
514 curr_pmic_info.dt_pmic_model[idx] & PMIC_MODEL_MASK;
515
516 /* Compare with board pmic information & Update bit mask */
517 if (curr_pmic_info.dt_pmic_model[idx] == (board_pmic_target(idx) & PMIC_MODEL_MASK))
518 curr_pmic_info.dt_match_val |= BIT (PMIC_MATCH_EXACT_MODEL_IDX0 + idx * PMIC_SHIFT_IDX);
519 else if (curr_pmic_info.dt_pmic_model[idx] == 0)
520 curr_pmic_info.dt_match_val |= BIT (PMIC_MATCH_DEFAULT_MODEL_IDX0 + idx * PMIC_SHIFT_IDX);
521 else
522 {
523 curr_pmic_info.dt_match_val |= BIT (NONE_MATCH);
524 dprintf(SPEW, "PMIC Model doesn't match\n");
525 break; /* go to next pmic entry */
526 }
527
528 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_EXACT_REV_IDX0 + idx * PMIC_SHIFT_IDX);
530 else if (curr_pmic_info.dt_pmic_rev[idx] < (board_pmic_target(idx) & PMIC_REV_MASK))
531 curr_pmic_info.dt_match_val |= BIT(PMIC_MATCH_BEST_REV_IDX0 + idx * PMIC_SHIFT_IDX);
lijuangf1b8e1d2018-03-01 14:40:37 +0800532 else {
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530533 dprintf(SPEW, "PMIC revision doesn't match\n");
534 break; /* go to next pmic entry */
lijuangf1b8e1d2018-03-01 14:40:37 +0800535 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530536 }
537
538 dprintf(SPEW, "Bestpmicinfo.dtmatchval : %x | cur_pmic_info.dtmatchval: %x\n",
539 best_pmic_info.dt_match_val, curr_pmic_info.dt_match_val);
540
541 /* Update best pmic info, if required */
542 if(best_pmic_info.dt_match_val < curr_pmic_info.dt_match_val)
543 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
544 else if (best_pmic_info.dt_match_val == curr_pmic_info.dt_match_val)
545 {
546 if (best_pmic_info.dt_pmic_rev[PMIC_IDX0] < curr_pmic_info.dt_pmic_rev[PMIC_IDX0])
547 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
548 else if (best_pmic_info.dt_pmic_rev[PMIC_IDX1] < curr_pmic_info.dt_pmic_rev[PMIC_IDX1])
549 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
550 else if (best_pmic_info.dt_pmic_rev[PMIC_IDX2] < curr_pmic_info.dt_pmic_rev[PMIC_IDX2])
551 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
552 else if (best_pmic_info.dt_pmic_rev[PMIC_IDX3] < curr_pmic_info.dt_pmic_rev[PMIC_IDX3])
553 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
554 }
555
556 /* Increment to next pmic entry */
557 pmic_prop += sizeof (struct pmic_id);
558 }
559
560 dprintf(SPEW, "Best pmic info 0x%0x/0x%x/0x%x/0x%0x for current dt\n",
561 best_pmic_info.dt_pmic_model[PMIC_IDX0],
562 best_pmic_info.dt_pmic_model[PMIC_IDX1],
563 best_pmic_info.dt_pmic_model[PMIC_IDX2],
564 best_pmic_info.dt_pmic_model[PMIC_IDX3]);
565
566 current_dtb_info->dt_match_val |= best_pmic_info.dt_match_val;
567 current_dtb_info->dt_pmic_rev[PMIC_IDX0] = best_pmic_info.dt_pmic_rev[PMIC_IDX0];
568 current_dtb_info->dt_pmic_model[PMIC_IDX0] = best_pmic_info.dt_pmic_model[PMIC_IDX0];
569 current_dtb_info->dt_pmic_rev[PMIC_IDX1] = best_pmic_info.dt_pmic_rev[PMIC_IDX1];
570 current_dtb_info->dt_pmic_model[PMIC_IDX1] = best_pmic_info.dt_pmic_model[PMIC_IDX1];
571 current_dtb_info->dt_pmic_rev[PMIC_IDX2] = best_pmic_info.dt_pmic_rev[PMIC_IDX2];
572 current_dtb_info->dt_pmic_model[PMIC_IDX2] = best_pmic_info.dt_pmic_model[PMIC_IDX2];
573 current_dtb_info->dt_pmic_rev[PMIC_IDX3] = best_pmic_info.dt_pmic_rev[PMIC_IDX3];
574 current_dtb_info->dt_pmic_model[PMIC_IDX3] = best_pmic_info.dt_pmic_model[PMIC_IDX3];
575 }
576 else
577 {
578 dprintf(SPEW, "qcom,pmic-id does not exit (or) is (%d) not a multiple of (%d)\n",
579 pmic_id_len, PMIC_ID_SIZE);
580 }
581
582cleanup:
583 if (current_dtb_info->dt_match_val & BIT(exact_match)) {
lijuang0cce8bf2018-08-23 10:56:42 +0800584 if (best_dtb_info->dt_match_val < current_dtb_info->dt_match_val) {
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530585 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
lijuang0cce8bf2018-08-23 10:56:42 +0800586 find_best_match = true;
587 } else if (best_dtb_info->dt_match_val == current_dtb_info->dt_match_val) {
588 find_best_match = true;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530589 if (best_dtb_info->dt_soc_rev < current_dtb_info->dt_soc_rev)
590 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
591 else if (best_dtb_info->dt_variant_major < current_dtb_info->dt_variant_major)
592 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
593 else if (best_dtb_info->dt_variant_minor < current_dtb_info->dt_variant_minor)
594 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
595 else if (best_dtb_info->dt_pmic_rev[0] < current_dtb_info->dt_pmic_rev[0])
596 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
597 else if (best_dtb_info->dt_pmic_rev[1] < current_dtb_info->dt_pmic_rev[1])
598 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
599 else if (best_dtb_info->dt_pmic_rev[2] < current_dtb_info->dt_pmic_rev[2])
600 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
601 else if (best_dtb_info->dt_pmic_rev[3] < current_dtb_info->dt_pmic_rev[3])
602 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
lijuang0cce8bf2018-08-23 10:56:42 +0800603 else
604 find_best_match = false;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530605 }
606 }
lijuang0cce8bf2018-08-23 10:56:42 +0800607
608 return find_best_match;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530609}
610
611void *get_soc_dtb(void *kernel, uint32_t kernel_size, uint32_t dtb_offset)
612{
613 uintptr_t kernel_end_offset = (uintptr_t)kernel + kernel_size;
614 void *dtb = NULL;
615 struct fdt_header dtb_header;
616 uint32_t dtb_size = 0;
617 dt_info cur_dtb_info = {0};
618 dt_info best_dtb_info = {0};
619
620 if (!dtb_offset){
621 dprintf(CRITICAL, "DTB offset is NULL\n");
622 return NULL;
623 }
624 if (((uintptr_t)kernel + (uintptr_t)dtb_offset) < (uintptr_t)kernel) {
625 return NULL;
626 }
627 dtb = kernel + dtb_offset;
628 while (((uintptr_t)dtb + sizeof(struct fdt_header)) < (uintptr_t)kernel_end_offset) {
629 /* the DTB could be unaligned, so extract the header,
630 * and operate on it separately */
631 memscpy(&dtb_header, sizeof(struct fdt_header), dtb, sizeof(struct fdt_header));
632 dtb_size = fdt_totalsize((const void *)&dtb_header);
633 if (fdt_check_header((const void *)&dtb_header) != 0 ||
634 fdt_check_header_ext((void *)&dtb_header) != 0 ||
635 ((uintptr_t)dtb + dtb_size < (uintptr_t)dtb) ||
636 ((uintptr_t)dtb + dtb_size > (uintptr_t)kernel_end_offset))
637 break;
638
639 cur_dtb_info.dtb = dtb;
640 dtb_read_find_match(&cur_dtb_info, &best_dtb_info, SOC_MATCH);
641 if (cur_dtb_info.dt_match_val) {
642 if (cur_dtb_info.dt_match_val & BIT(SOC_MATCH)) {
643 if (check_all_bits_set(cur_dtb_info.dt_match_val)) {
644 dprintf(CRITICAL, "Exact DTB match found. dtbo search is not required\n");
645 dtbo_needed = false;
646 }
647 }
648 }
649 dprintf(SPEW, "Best Match DTB VAL = %x\n", best_dtb_info.dt_match_val);
650 dtb += dtb_size;
651 }
652 if (!best_dtb_info.dtb) {
653 dprintf(CRITICAL, "No match found for soc dtb type\n");
654 return NULL;
655 }
656 return best_dtb_info.dtb;
657}
658
659void *get_board_dtb(void *dtbo_image_buf)
660{
661 struct dtbo_table_hdr *dtbo_table_header = dtbo_image_buf;
662 struct dtbo_table_entry *dtb_table_entry = NULL;
663 uint32_t dtbo_count = 0;
664 void *board_dtb = NULL;
665 uint32_t dtbo_table_entries_count = 0;
666 uint32_t first_dtbo_table_entry_offset = 0;
667 struct fdt_header dtb_header;
668 uint32_t dtb_size = 0;
669 dt_info cur_dtb_info = {0};
670 dt_info best_dtb_info = {0};
lijuang0cce8bf2018-08-23 10:56:42 +0800671 boolean find_best_dtb = false;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530672
673 if (!dtbo_image_buf) {
674 dprintf(CRITICAL, "dtbo image buffer is NULL\n");
675 return NULL;
676 }
677
678 first_dtbo_table_entry_offset = fdt32_to_cpu(dtbo_table_header->dt_entry_offset);
679 if ((uintptr_t)dtbo_image_buf > ((uintptr_t)dtbo_image_buf + (uintptr_t)first_dtbo_table_entry_offset))
680 {
681 dprintf(CRITICAL, "dtbo table entry offset is invalid\n");
682 return NULL;
683 }
684 dtb_table_entry = (struct dtbo_table_entry *)(dtbo_image_buf + first_dtbo_table_entry_offset);
685 dtbo_table_entries_count = fdt32_to_cpu(dtbo_table_header->dt_entry_count);
686 for (dtbo_count = 0; dtbo_count < dtbo_table_entries_count; dtbo_count++) {
687 board_dtb = dtbo_image_buf + fdt32_to_cpu(dtb_table_entry->dt_offset);
688 /* The DTB could be unaligned, so extract the header,
689 * and operate on it separately */
690 memscpy(&dtb_header, sizeof(struct fdt_header), board_dtb, sizeof(struct fdt_header));
691 dtb_size = fdt_totalsize((const void *)&dtb_header);
692 if (fdt_check_header((const void *)&dtb_header) != 0 ||
693 fdt_check_header_ext((void *)&dtb_header) != 0 ||
694 ((uintptr_t)board_dtb + dtb_size < (uintptr_t)board_dtb)) {
695 dprintf(CRITICAL, "No valid board dtb found\n");
696 break;
697 }
698 dprintf(SPEW, "Valid board dtb is found\n");
699 cur_dtb_info.dtb = board_dtb;
lijuang0cce8bf2018-08-23 10:56:42 +0800700 find_best_dtb = dtb_read_find_match(&cur_dtb_info, &best_dtb_info, VARIANT_MATCH);
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530701 dprintf(SPEW, "dtbo count = %u local_board_dt_match =%x\n",dtbo_count, cur_dtb_info.dt_match_val);
702 dtb_table_entry++;
lijuang0cce8bf2018-08-23 10:56:42 +0800703
704 if (find_best_dtb) {
705 dtbo_idx = dtbo_count;
706 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530707 }
708 if (!best_dtb_info.dtb) {
709 dprintf(CRITICAL, "Unable to find the board dtb\n");
710 return NULL;
711 }
712 return best_dtb_info.dtb;
713}
714
Lijuan Gao9f152862014-08-18 13:45:24 +0800715static void insert_dt_entry_in_queue(struct dt_entry_node *dt_list, struct dt_entry_node *dt_node_member)
716{
717 list_add_tail(&dt_list->node, &dt_node_member->node);
718}
719
720static void dt_entry_list_delete(struct dt_entry_node *dt_node_member)
721{
722 if (list_in_list(&dt_node_member->node)) {
723 list_delete(&dt_node_member->node);
724 free(dt_node_member->dt_entry_m);
725 free(dt_node_member);
726 }
727}
728
729static int dev_tree_compatible(void *dtb, uint32_t dtb_size, struct dt_entry_node *dtb_list)
Dima Zavinc46f8382013-05-03 12:23:06 -0700730{
731 int root_offset;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700732 const void *prop = NULL;
733 const char *plat_prop = NULL;
734 const char *board_prop = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800735 const char *pmic_prop = NULL;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700736 char *model = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800737 struct dt_entry *cur_dt_entry;
738 struct dt_entry *dt_entry_array = NULL;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700739 struct board_id *board_data = NULL;
740 struct plat_id *platform_data = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800741 struct pmic_id *pmic_data = NULL;
Dima Zavinc46f8382013-05-03 12:23:06 -0700742 int len;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700743 int len_board_id;
744 int len_plat_id;
745 int min_plat_id_len = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800746 int len_pmic_id;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700747 uint32_t dtb_ver;
748 uint32_t num_entries = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800749 uint32_t i, j, k, n;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700750 uint32_t msm_data_count;
751 uint32_t board_data_count;
Lijuan Gao9f152862014-08-18 13:45:24 +0800752 uint32_t pmic_data_count;
Dima Zavinc46f8382013-05-03 12:23:06 -0700753
754 root_offset = fdt_path_offset(dtb, "/");
755 if (root_offset < 0)
756 return false;
757
758 prop = fdt_getprop(dtb, root_offset, "model", &len);
759 if (prop && len > 0) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700760 model = (char *) malloc(sizeof(char) * len);
761 ASSERT(model);
762 strlcpy(model, prop, len);
Dima Zavinc46f8382013-05-03 12:23:06 -0700763 } else {
vijay kumar89d36d82014-06-30 19:32:18 +0530764 dprintf(INFO, "model does not exist in device tree\n");
Dima Zavinc46f8382013-05-03 12:23:06 -0700765 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800766 /* Find the pmic-id prop from DTB , if pmic-id is present then
767 * the DTB is version 3, otherwise find the board-id prop from DTB ,
768 * if board-id is present then the DTB is version 2 */
769 pmic_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,pmic-id", &len_pmic_id);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700770 board_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,board-id", &len_board_id);
Lijuan Gao9f152862014-08-18 13:45:24 +0800771 if (pmic_prop && (len_pmic_id > 0) && board_prop && (len_board_id > 0)) {
772 if ((len_pmic_id % PMIC_ID_SIZE) || (len_board_id % BOARD_ID_SIZE))
773 {
774 dprintf(CRITICAL, "qcom,pmic-id(%d) or qcom,board-id(%d) in device tree is not a multiple of (%d %d)\n",
775 len_pmic_id, len_board_id, PMIC_ID_SIZE, BOARD_ID_SIZE);
776 return false;
777 }
778 dtb_ver = DEV_TREE_VERSION_V3;
779 min_plat_id_len = PLAT_ID_SIZE;
780 } else if (board_prop && len_board_id > 0) {
vijay kumar89d36d82014-06-30 19:32:18 +0530781 if (len_board_id % BOARD_ID_SIZE)
782 {
783 dprintf(CRITICAL, "qcom,board-id in device tree is (%d) not a multiple of (%d)\n",
784 len_board_id, BOARD_ID_SIZE);
785 return false;
786 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700787 dtb_ver = DEV_TREE_VERSION_V2;
788 min_plat_id_len = PLAT_ID_SIZE;
Lijuan Gao9f152862014-08-18 13:45:24 +0800789 } else {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700790 dtb_ver = DEV_TREE_VERSION_V1;
791 min_plat_id_len = DT_ENTRY_V1_SIZE;
792 }
793
794 /* Get the msm-id prop from DTB */
795 plat_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,msm-id", &len_plat_id);
796 if (!plat_prop || len_plat_id <= 0) {
Dima Zavinc46f8382013-05-03 12:23:06 -0700797 dprintf(INFO, "qcom,msm-id entry not found\n");
798 return false;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700799 } else if (len_plat_id % min_plat_id_len) {
800 dprintf(INFO, "qcom,msm-id in device tree is (%d) not a multiple of (%d)\n",
801 len_plat_id, min_plat_id_len);
Dima Zavinc46f8382013-05-03 12:23:06 -0700802 return false;
803 }
Dima Zavinc46f8382013-05-03 12:23:06 -0700804
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700805 /*
806 * If DTB version is '1' look for <x y z> pair in the DTB
807 * x: platform_id
808 * y: variant_id
809 * z: SOC rev
810 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800811 if (dtb_ver == DEV_TREE_VERSION_V1) {
812 cur_dt_entry = (struct dt_entry *)
813 malloc(sizeof(struct dt_entry));
Dima Zavinc46f8382013-05-03 12:23:06 -0700814
Lijuan Gao9f152862014-08-18 13:45:24 +0800815 if (!cur_dt_entry) {
816 dprintf(CRITICAL, "Out of memory\n");
817 return false;
818 }
819 memset(cur_dt_entry, 0, sizeof(struct dt_entry));
820
821 while (len_plat_id) {
822 cur_dt_entry->platform_id = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->platform_id);
823 cur_dt_entry->variant_id = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->variant_id);
824 cur_dt_entry->soc_rev = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->soc_rev);
825 cur_dt_entry->board_hw_subtype =
826 fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->variant_id) >> 0x18;
827 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
828 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
829 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
830 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
831 cur_dt_entry->offset = (uint32_t)dtb;
832 cur_dt_entry->size = dtb_size;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700833
834 dprintf(SPEW, "Found an appended flattened device tree (%s - %u %u 0x%x)\n",
Lijuan Gao9f152862014-08-18 13:45:24 +0800835 *model ? model : "unknown",
836 cur_dt_entry->platform_id, cur_dt_entry->variant_id, cur_dt_entry->soc_rev);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700837
Lijuan Gao9f152862014-08-18 13:45:24 +0800838 if (platform_dt_absolute_match(cur_dt_entry, dtb_list)) {
839 dprintf(SPEW, "Device tree exact match the board: <%u %u 0x%x> != <%u %u 0x%x>\n",
840 cur_dt_entry->platform_id,
841 cur_dt_entry->variant_id,
842 cur_dt_entry->soc_rev,
843 board_platform_id(),
844 board_hardware_id(),
845 board_soc_version());
846
847 } else {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700848 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 +0800849 cur_dt_entry->platform_id,
850 cur_dt_entry->variant_id,
851 cur_dt_entry->soc_rev,
852 board_platform_id(),
853 board_hardware_id(),
854 board_soc_version());
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700855 plat_prop += DT_ENTRY_V1_SIZE;
856 len_plat_id -= DT_ENTRY_V1_SIZE;
857 continue;
858 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700859 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800860 free(cur_dt_entry);
861
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700862 }
863 /*
Lijuan Gao9f152862014-08-18 13:45:24 +0800864 * If DTB Version is '3' then we have split DTB with board & msm data & pmic
865 * populated saperately in board-id & msm-id & pmic-id prop respectively.
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700866 * Extract the data & prepare a look up table
867 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800868 else if (dtb_ver == DEV_TREE_VERSION_V2 || dtb_ver == DEV_TREE_VERSION_V3) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700869 board_data_count = (len_board_id / BOARD_ID_SIZE);
870 msm_data_count = (len_plat_id / PLAT_ID_SIZE);
Lijuan Gao9f152862014-08-18 13:45:24 +0800871 /* If dtb version is v2.0, the pmic_data_count will be <= 0 */
872 pmic_data_count = (len_pmic_id / PMIC_ID_SIZE);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700873
Lijuan Gao9f152862014-08-18 13:45:24 +0800874 /* If we are using dtb v3.0, then we have split board, msm & pmic data in the DTB
875 * If we are using dtb v2.0, then we have split board & msmdata in the DTB
876 */
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700877 board_data = (struct board_id *) malloc(sizeof(struct board_id) * (len_board_id / BOARD_ID_SIZE));
878 ASSERT(board_data);
879 platform_data = (struct plat_id *) malloc(sizeof(struct plat_id) * (len_plat_id / PLAT_ID_SIZE));
880 ASSERT(platform_data);
Lijuan Gao9f152862014-08-18 13:45:24 +0800881 if (dtb_ver == DEV_TREE_VERSION_V3) {
882 pmic_data = (struct pmic_id *) malloc(sizeof(struct pmic_id) * (len_pmic_id / PMIC_ID_SIZE));
883 ASSERT(pmic_data);
884 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700885 i = 0;
886
887 /* Extract board data from DTB */
Lijuan Gao9f152862014-08-18 13:45:24 +0800888 for(i = 0 ; i < board_data_count; i++) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700889 board_data[i].variant_id = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id);
890 board_data[i].platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->platform_subtype);
Lijuan Gao9f152862014-08-18 13:45:24 +0800891 /* For V2/V3 version of DTBs we have platform version field as part
892 * of variant ID, in such case the subtype will be mentioned as 0x0
893 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
894 * SS -- Subtype
895 * PM -- Platform major version
896 * Pm -- Platform minor version
897 * PH -- Platform hardware CDP/MTP
898 * In such case to make it compatible with LK algorithm move the subtype
899 * from variant_id to subtype field
900 */
901 if (board_data[i].platform_subtype == 0)
902 board_data[i].platform_subtype =
903 fdt32_to_cpu(((struct board_id *)board_prop)->variant_id) >> 0x18;
904
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700905 len_board_id -= sizeof(struct board_id);
906 board_prop += sizeof(struct board_id);
907 }
908
909 /* Extract platform data from DTB */
Lijuan Gao9f152862014-08-18 13:45:24 +0800910 for(i = 0 ; i < msm_data_count; i++) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700911 platform_data[i].platform_id = fdt32_to_cpu(((struct plat_id *)plat_prop)->platform_id);
912 platform_data[i].soc_rev = fdt32_to_cpu(((struct plat_id *)plat_prop)->soc_rev);
913 len_plat_id -= sizeof(struct plat_id);
914 plat_prop += sizeof(struct plat_id);
915 }
916
Lijuan Gao9f152862014-08-18 13:45:24 +0800917 if (dtb_ver == DEV_TREE_VERSION_V3 && pmic_prop) {
918 /* Extract pmic data from DTB */
919 for(i = 0 ; i < pmic_data_count; i++) {
920 pmic_data[i].pmic_version[0]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[0]);
921 pmic_data[i].pmic_version[1]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[1]);
922 pmic_data[i].pmic_version[2]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[2]);
923 pmic_data[i].pmic_version[3]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[3]);
924 len_pmic_id -= sizeof(struct pmic_id);
925 pmic_prop += sizeof(struct pmic_id);
926 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700927
Lijuan Gao9f152862014-08-18 13:45:24 +0800928 /* We need to merge board & platform data into dt entry structure */
929 num_entries = msm_data_count * board_data_count * pmic_data_count;
930 } else {
931 /* We need to merge board & platform data into dt entry structure */
932 num_entries = msm_data_count * board_data_count;
933 }
vijay kumar89d36d82014-06-30 19:32:18 +0530934
Lijuan Gao9f152862014-08-18 13:45:24 +0800935 if ((((uint64_t)msm_data_count * (uint64_t)board_data_count * (uint64_t)pmic_data_count) !=
936 msm_data_count * board_data_count * pmic_data_count) ||
937 (((uint64_t)msm_data_count * (uint64_t)board_data_count) != msm_data_count * board_data_count)) {
938
939 free(board_data);
940 free(platform_data);
941 if (pmic_data)
942 free(pmic_data);
943 if (model)
944 free(model);
945 return false;
946 }
947
948 dt_entry_array = (struct dt_entry*) malloc(sizeof(struct dt_entry) * num_entries);
949 ASSERT(dt_entry_array);
950
951 /* If we have '<X>; <Y>; <Z>' as platform data & '<A>; <B>; <C>' as board data.
952 * Then dt entry should look like
953 * <X ,A >;<X, B>;<X, C>;
954 * <Y ,A >;<Y, B>;<Y, C>;
955 * <Z ,A >;<Z, B>;<Z, C>;
956 */
957 i = 0;
958 k = 0;
959 n = 0;
960 for (i = 0; i < msm_data_count; i++) {
961 for (j = 0; j < board_data_count; j++) {
962 if (dtb_ver == DEV_TREE_VERSION_V3 && pmic_prop) {
963 for (n = 0; n < pmic_data_count; n++) {
964 dt_entry_array[k].platform_id = platform_data[i].platform_id;
965 dt_entry_array[k].soc_rev = platform_data[i].soc_rev;
966 dt_entry_array[k].variant_id = board_data[j].variant_id;
967 dt_entry_array[k].board_hw_subtype = board_data[j].platform_subtype;
968 dt_entry_array[k].pmic_rev[0]= pmic_data[n].pmic_version[0];
969 dt_entry_array[k].pmic_rev[1]= pmic_data[n].pmic_version[1];
970 dt_entry_array[k].pmic_rev[2]= pmic_data[n].pmic_version[2];
971 dt_entry_array[k].pmic_rev[3]= pmic_data[n].pmic_version[3];
972 dt_entry_array[k].offset = (uint32_t)dtb;
973 dt_entry_array[k].size = dtb_size;
974 k++;
975 }
976
977 } else {
978 dt_entry_array[k].platform_id = platform_data[i].platform_id;
979 dt_entry_array[k].soc_rev = platform_data[i].soc_rev;
980 dt_entry_array[k].variant_id = board_data[j].variant_id;
981 dt_entry_array[k].board_hw_subtype = board_data[j].platform_subtype;
982 dt_entry_array[k].pmic_rev[0]= board_pmic_target(0);
983 dt_entry_array[k].pmic_rev[1]= board_pmic_target(1);
984 dt_entry_array[k].pmic_rev[2]= board_pmic_target(2);
985 dt_entry_array[k].pmic_rev[3]= board_pmic_target(3);
986 dt_entry_array[k].offset = (uint32_t)dtb;
987 dt_entry_array[k].size = dtb_size;
vijay kumar89d36d82014-06-30 19:32:18 +0530988 k++;
989 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700990 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800991 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700992
Lijuan Gao9f152862014-08-18 13:45:24 +0800993 for (i=0 ;i < num_entries; i++) {
994 dprintf(SPEW, "Found an appended flattened device tree (%s - %u %u %u 0x%x)\n",
995 *model ? model : "unknown",
996 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 +0530997
Lijuan Gao9f152862014-08-18 13:45:24 +0800998 if (platform_dt_absolute_match(&(dt_entry_array[i]), dtb_list)) {
999 dprintf(SPEW, "Device tree exact match the board: <%u %u %u 0x%x> == <%u %u %u 0x%x>\n",
1000 dt_entry_array[i].platform_id,
1001 dt_entry_array[i].variant_id,
1002 dt_entry_array[i].soc_rev,
1003 dt_entry_array[i].board_hw_subtype,
1004 board_platform_id(),
1005 board_hardware_id(),
1006 board_hardware_subtype(),
1007 board_soc_version());
vijay kumar89d36d82014-06-30 19:32:18 +05301008
Lijuan Gao9f152862014-08-18 13:45:24 +08001009 } else {
1010 dprintf(SPEW, "Device tree's msm_id doesn't match the board: <%u %u %u 0x%x> != <%u %u %u 0x%x>\n",
1011 dt_entry_array[i].platform_id,
1012 dt_entry_array[i].variant_id,
1013 dt_entry_array[i].soc_rev,
1014 dt_entry_array[i].board_hw_subtype,
1015 board_platform_id(),
1016 board_hardware_id(),
1017 board_hardware_subtype(),
1018 board_soc_version());
Channagoud Kadabia4dbe332013-09-05 17:44:11 -07001019 }
1020 }
Lijuan Gao9f152862014-08-18 13:45:24 +08001021
1022 free(board_data);
1023 free(platform_data);
1024 if (pmic_data)
1025 free(pmic_data);
1026 free(dt_entry_array);
Dima Zavinc46f8382013-05-03 12:23:06 -07001027 }
Lijuan Gao9f152862014-08-18 13:45:24 +08001028 if (model)
vijay kumar89d36d82014-06-30 19:32:18 +05301029 free(model);
Lijuan Gao9f152862014-08-18 13:45:24 +08001030 return true;
Dima Zavinc46f8382013-05-03 12:23:06 -07001031}
1032
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301033/* function to handle the overlay in independent thread */
1034static int dtb_overlay_handler(void *args)
1035{
1036 dprintf(SPEW, "thread %s() started\n", __func__);
1037
1038 soc_dtb_hdr = ufdt_install_blob(soc_dtb, fdt_totalsize(soc_dtb));
1039 if(!soc_dtb_hdr)
1040 {
1041 dprintf(CRITICAL, "ERROR: Install Blob failed\n");
1042 ret = DTBO_ERROR;
1043 goto out;
1044 }
1045 final_dtb_hdr = ufdt_apply_overlay(soc_dtb_hdr, fdt_totalsize(soc_dtb_hdr),board_dtb,
1046 fdt_totalsize(board_dtb));
1047 if (!final_dtb_hdr)
1048 {
1049 dprintf(CRITICAL, "ERROR: UFDT apply overlay failed\n");
1050 ret = DTBO_ERROR;
1051 goto out;
1052 }
1053out:
1054 /* This flag can only be updated here, hence it is not protected */
1055 event_signal(&dtbo_event, true);
1056 thread_exit(0);
1057 return 0;
1058}
1059
1060/*
1061 * Function to check and form new dtb with Overlay support.
1062*/
1063dtbo_error dev_tree_appended_with_dtbo(void *kernel, uint32_t kernel_size,
1064 uint32_t dtb_offset, void *tags)
1065{
1066 void *dtbo_image_buf = NULL;
Mayank Groverb61c0c22018-09-04 15:09:32 +05301067 uint32_t dtbo_image_sz = 0;
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301068
Mayank Grover302432a2017-12-08 17:18:58 +05301069 bs_set_timestamp(BS_DTB_OVERLAY_START);
Mayank Groverb61c0c22018-09-04 15:09:32 +05301070 ret = load_validate_dtbo_image(&dtbo_image_buf, &dtbo_image_sz);
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301071 if (ret == DTBO_SUCCESS)
1072 {
1073 final_dtb_hdr = soc_dtb = get_soc_dtb(kernel,
1074 kernel_size, dtb_offset);
1075 if(!soc_dtb)
1076 {
1077 ret = DTBO_ERROR;
1078 goto out;
1079 }
1080
1081 if (dtbo_needed)
1082 {
1083 board_dtb = get_board_dtb(dtbo_image_buf);
1084 if(!board_dtb)
1085 {
1086 ret = DTBO_ERROR;
1087 goto out;
1088 }
1089
1090 if((ADD_OF((fdt_totalsize(soc_dtb)), (fdt_totalsize(board_dtb)))) > MAX_DTBO_SZ)
1091 {
1092 dprintf(CRITICAL, "ERROR: dtb greater than max supported.\n");
1093 ret = DTBO_ERROR;
1094 goto out;
1095 }
1096
1097 /*
1098 spawn a seperate thread for dtbo overlay with indpendent,
1099 stack to avoid issues with stack corruption seen during flattening,
1100 of dtb in overlay functionality
1101 */
1102 {
1103 thread_t *thr = NULL;
1104 event_init(&dtbo_event, 0, EVENT_FLAG_AUTOUNSIGNAL);
1105 thr = thread_create("dtb_overlay", dtb_overlay_handler, 0,
1106 DEFAULT_PRIORITY, DTBO_STACK_SIZE);
1107 if (!thr)
1108 {
1109 dprintf(CRITICAL, "ERROR: Failed to create DTBO thread.\n");
1110 ret = DTBO_ERROR;
1111 goto out;
1112 }
1113 thread_resume(thr);
1114
1115 /* block current thread, untill woken up by dtb_overlay_handler. */
1116 event_wait(&dtbo_event);
1117
1118 /* ret is updated by dtb overlay thread, in case of error */
1119 if(ret == DTBO_ERROR)
1120 {
1121 goto out;
1122 }
1123 } /* dtbo_overlay_handler exited */
1124
1125 }
1126 memscpy(tags, fdt_totalsize(final_dtb_hdr), final_dtb_hdr,
1127 fdt_totalsize(final_dtb_hdr));
Mayank Grover71f63862018-05-03 17:06:41 +05301128 dprintf(INFO, "DTB overlay is successful\n");
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301129 }
1130 else
1131 {
Mayank Grover71f63862018-05-03 17:06:41 +05301132 dprintf(INFO, "ERROR: DTBO read is not valid\n DTB Overlay failed.\n");
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301133 ret = DTBO_NOT_SUPPORTED;
1134 }
1135out:
Mayank Grover302432a2017-12-08 17:18:58 +05301136 bs_set_timestamp(BS_DTB_OVERLAY_END);
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301137 return ret;
1138}
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001139/*
Dima Zavin77e41f32013-03-06 16:10:43 -08001140 * Will relocate the DTB to the tags addr if the device tree is found and return
1141 * its address
1142 *
1143 * Arguments: kernel - Start address of the kernel loaded in RAM
1144 * tags - Start address of the tags loaded in RAM
Channagoud Kadabi704cd562013-04-25 15:19:59 -07001145 * kernel_size - Size of the kernel in bytes
1146 *
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001147 * Return Value: DTB address : If appended device tree is found
Dima Zavin77e41f32013-03-06 16:10:43 -08001148 * 'NULL' : Otherwise
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001149 */
Matthew Qinbb7923d2015-02-09 10:56:09 +08001150void *dev_tree_appended(void *kernel, uint32_t kernel_size, uint32_t dtb_offset, void *tags)
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001151{
Parth Dixit97e47bb2016-03-07 17:20:44 +05301152 uintptr_t kernel_end = (uintptr_t)kernel + kernel_size;
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001153 uint32_t app_dtb_offset = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +08001154 void *dtb = NULL;
Shashank Mittalc0f10282013-07-15 14:53:31 -07001155 void *bestmatch_tag = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +08001156 struct dt_entry *best_match_dt_entry = NULL;
Shashank Mittalc0f10282013-07-15 14:53:31 -07001157 uint32_t bestmatch_tag_size;
Lijuan Gao9f152862014-08-18 13:45:24 +08001158 struct dt_entry_node *dt_entry_queue = NULL;
1159 struct dt_entry_node *dt_node_tmp1 = NULL;
1160 struct dt_entry_node *dt_node_tmp2 = NULL;
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301161 dtbo_error ret = DTBO_NOT_SUPPORTED;
1162
lijuangdc1b5422018-05-07 17:12:59 +08001163 if (dtb_offset)
1164 app_dtb_offset = dtb_offset;
1165 else
1166 memcpy((void*) &app_dtb_offset, (void*) (kernel + DTB_OFFSET), sizeof(uint32_t));
1167
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301168 /* Check for dtbo support */
lijuangdc1b5422018-05-07 17:12:59 +08001169 ret = dev_tree_appended_with_dtbo(kernel, kernel_size, app_dtb_offset, tags);
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301170 if (ret == DTBO_SUCCESS)
1171 return tags;
1172 else if (ret == DTBO_ERROR)
1173 return NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +08001174
Lijuan Gao9f152862014-08-18 13:45:24 +08001175 /* Initialize the dtb entry node*/
1176 dt_entry_queue = (struct dt_entry_node *)
1177 malloc(sizeof(struct dt_entry_node));
1178
1179 if (!dt_entry_queue) {
1180 dprintf(CRITICAL, "Out of memory\n");
1181 return NULL;
1182 }
1183 list_initialize(&dt_entry_queue->node);
1184
vijay kumare2a5ea82014-06-25 12:24:14 +05301185 if (((uintptr_t)kernel + (uintptr_t)app_dtb_offset) < (uintptr_t)kernel) {
1186 return NULL;
1187 }
Parth Dixit97e47bb2016-03-07 17:20:44 +05301188 dtb = (void *)((uintptr_t)kernel + app_dtb_offset);
1189
vijay kumare2a5ea82014-06-25 12:24:14 +05301190 while (((uintptr_t)dtb + sizeof(struct fdt_header)) < (uintptr_t)kernel_end) {
Dima Zavinc46f8382013-05-03 12:23:06 -07001191 struct fdt_header dtb_hdr;
1192 uint32_t dtb_size;
Dima Zavin77e41f32013-03-06 16:10:43 -08001193
Dima Zavinc46f8382013-05-03 12:23:06 -07001194 /* the DTB could be unaligned, so extract the header,
1195 * and operate on it separately */
1196 memcpy(&dtb_hdr, dtb, sizeof(struct fdt_header));
1197 if (fdt_check_header((const void *)&dtb_hdr) != 0 ||
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +05301198 fdt_check_header_ext((const void *)&dtb_hdr) != 0 ||
vijay kumare2a5ea82014-06-25 12:24:14 +05301199 ((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) < (uintptr_t)dtb) ||
1200 ((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) > (uintptr_t)kernel_end))
Dima Zavinc46f8382013-05-03 12:23:06 -07001201 break;
1202 dtb_size = fdt_totalsize(&dtb_hdr);
1203
Lijuan Gao9f152862014-08-18 13:45:24 +08001204 dev_tree_compatible(dtb, dtb_size, dt_entry_queue);
Dima Zavinc46f8382013-05-03 12:23:06 -07001205
1206 /* goto the next device tree if any */
1207 dtb += dtb_size;
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001208 }
Dima Zavinc46f8382013-05-03 12:23:06 -07001209
Lijuan Gao9f152862014-08-18 13:45:24 +08001210 best_match_dt_entry = platform_dt_match_best(dt_entry_queue);
1211 if (best_match_dt_entry){
1212 bestmatch_tag = (void *)best_match_dt_entry->offset;
1213 bestmatch_tag_size = best_match_dt_entry->size;
1214 dprintf(INFO, "Best match DTB tags %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1215 best_match_dt_entry->platform_id, best_match_dt_entry->variant_id,
1216 best_match_dt_entry->board_hw_subtype, best_match_dt_entry->soc_rev,
1217 best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],
1218 best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],
1219 best_match_dt_entry->offset, best_match_dt_entry->size);
1220 dprintf(INFO, "Using pmic info 0x%0x/0x%x/0x%x/0x%0x for device 0x%0x/0x%x/0x%x/0x%0x\n",
1221 best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],
1222 best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],
1223 board_pmic_target(0), board_pmic_target(1),
1224 board_pmic_target(2), board_pmic_target(3));
1225 }
1226 /* free queue's memory */
1227 list_for_every_entry(&dt_entry_queue->node, dt_node_tmp1, dt_node, node) {
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001228 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001229 dt_entry_list_delete(dt_node_tmp1);
1230 dt_node_tmp1 = dt_node_tmp2;
1231 }
1232
Shashank Mittalc0f10282013-07-15 14:53:31 -07001233 if(bestmatch_tag) {
Parth Dixitc2f0cb92016-03-10 10:40:14 +05301234 if (check_aboot_addr_range_overlap((uintptr_t)tags, bestmatch_tag_size)) {
1235 dprintf(CRITICAL, "Tags addresses overlap with aboot addresses.\n");
1236 return NULL;
1237 }
Shashank Mittalc0f10282013-07-15 14:53:31 -07001238 memcpy(tags, bestmatch_tag, bestmatch_tag_size);
1239 /* clear out the old DTB magic so kernel doesn't find it */
1240 *((uint32_t *)(kernel + app_dtb_offset)) = 0;
1241 return tags;
1242 }
1243
Dima Zavinc46f8382013-05-03 12:23:06 -07001244 dprintf(CRITICAL, "DTB offset is incorrect, kernel image does not have appended DTB\n");
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001245
David Ng59c4a782015-05-14 15:51:44 -07001246 dprintf(INFO, "Device info 0x%08x/%08x/0x%08x/%u, pmic 0x%0x/0x%x/0x%x/0x%0x\n",
1247 board_platform_id(), board_soc_version(),
1248 board_target_id(), board_hardware_subtype(),
1249 board_pmic_target(0), board_pmic_target(1),
1250 board_pmic_target(2), board_pmic_target(3));
Dima Zavin77e41f32013-03-06 16:10:43 -08001251 return NULL;
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001252}
1253
Joel Kingaa335dc2013-06-03 16:11:08 -07001254/* Returns 0 if the device tree is valid. */
Deepa Dinamani87252952013-09-09 13:58:27 -07001255int dev_tree_validate(struct dt_table *table, unsigned int page_size, uint32_t *dt_hdr_size)
Joel Kingaa335dc2013-06-03 16:11:08 -07001256{
1257 int dt_entry_size;
Channagoud Kadabid87c2772014-06-20 15:41:55 -07001258 uint64_t hdr_size;
Joel Kingaa335dc2013-06-03 16:11:08 -07001259
1260 /* Validate the device tree table header */
1261 if(table->magic != DEV_TREE_MAGIC) {
1262 dprintf(CRITICAL, "ERROR: Bad magic in device tree table \n");
1263 return -1;
1264 }
1265
1266 if (table->version == DEV_TREE_VERSION_V1) {
1267 dt_entry_size = sizeof(struct dt_entry_v1);
1268 } else if (table->version == DEV_TREE_VERSION_V2) {
Lijuan Gao9f152862014-08-18 13:45:24 +08001269 dt_entry_size = sizeof(struct dt_entry_v2);
1270 } else if (table->version == DEV_TREE_VERSION_V3) {
Joel Kingaa335dc2013-06-03 16:11:08 -07001271 dt_entry_size = sizeof(struct dt_entry);
1272 } else {
1273 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
1274 table->version);
1275 return -1;
1276 }
1277
Channagoud Kadabid87c2772014-06-20 15:41:55 -07001278 hdr_size = (uint64_t)table->num_entries * dt_entry_size + DEV_TREE_HEADER_SIZE;
1279
Deepa Dinamani87252952013-09-09 13:58:27 -07001280 /* Roundup to page_size. */
1281 hdr_size = ROUNDUP(hdr_size, page_size);
1282
Channagoud Kadabid87c2772014-06-20 15:41:55 -07001283 if (hdr_size > UINT_MAX)
1284 return -1;
1285 else
1286 *dt_hdr_size = hdr_size & UINT_MAX;
Joel Kingaa335dc2013-06-03 16:11:08 -07001287
1288 return 0;
1289}
1290
Lijuan Gao9f152862014-08-18 13:45:24 +08001291static int platform_dt_absolute_match(struct dt_entry *cur_dt_entry, struct dt_entry_node *dt_list)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001292{
Lijuan Gaof8e95722014-12-23 03:03:12 -05001293 uint32_t cur_dt_hlos_ddr;
Lijuan Gao9f152862014-08-18 13:45:24 +08001294 uint32_t cur_dt_hw_platform;
1295 uint32_t cur_dt_hw_subtype;
1296 uint32_t cur_dt_msm_id;
1297 dt_node *dt_node_tmp = NULL;
Channagoud Kadabi571193a2014-02-05 13:58:49 -08001298
Lijuan Gao9f152862014-08-18 13:45:24 +08001299 /* Platform-id
1300 * bit no |31 24|23 16|15 0|
1301 * |reserved|foundry-id|msm-id|
1302 */
1303 cur_dt_msm_id = (cur_dt_entry->platform_id & 0x0000ffff);
1304 cur_dt_hw_platform = (cur_dt_entry->variant_id & 0x000000ff);
Lijuan Gao0621b862014-09-02 10:02:52 +08001305 cur_dt_hw_subtype = (cur_dt_entry->board_hw_subtype & 0xff);
Lijuan Gao9f152862014-08-18 13:45:24 +08001306
Lijuan Gaof8e95722014-12-23 03:03:12 -05001307 /* Determine the bits 10:8 to check the DT with the DDR Size */
1308 cur_dt_hlos_ddr = (cur_dt_entry->board_hw_subtype & 0x700);
Channagoud Kadabi571193a2014-02-05 13:58:49 -08001309
Lijuan Gao9f152862014-08-18 13:45:24 +08001310 /* 1. must match the msm_id, platform_hw_id, platform_subtype and DDR size
1311 * soc, board major/minor, pmic major/minor must less than board info
1312 * 2. find the matched DTB then return 1
1313 * 3. otherwise return 0
Maria Yu2e2d2c22013-07-03 19:20:33 +08001314 */
Lijuan Gao9f152862014-08-18 13:45:24 +08001315 if((cur_dt_msm_id == (board_platform_id() & 0x0000ffff)) &&
1316 (cur_dt_hw_platform == board_hardware_id()) &&
1317 (cur_dt_hw_subtype == board_hardware_subtype()) &&
Lijuan Gaof8e95722014-12-23 03:03:12 -05001318 (cur_dt_hlos_ddr == (target_get_hlos_subtype() & 0x700)) &&
Lijuan Gao9f152862014-08-18 13:45:24 +08001319 (cur_dt_entry->soc_rev <= board_soc_version()) &&
1320 ((cur_dt_entry->variant_id & 0x00ffff00) <= (board_target_id() & 0x00ffff00)) &&
1321 ((cur_dt_entry->pmic_rev[0] & 0x00ffff00) <= (board_pmic_target(0) & 0x00ffff00)) &&
1322 ((cur_dt_entry->pmic_rev[1] & 0x00ffff00) <= (board_pmic_target(1) & 0x00ffff00)) &&
1323 ((cur_dt_entry->pmic_rev[2] & 0x00ffff00) <= (board_pmic_target(2) & 0x00ffff00)) &&
1324 ((cur_dt_entry->pmic_rev[3] & 0x00ffff00) <= (board_pmic_target(3) & 0x00ffff00))) {
Maria Yu2e2d2c22013-07-03 19:20:33 +08001325
Lijuan Gao9f152862014-08-18 13:45:24 +08001326 dt_node_tmp = dt_entry_list_init();
1327 memcpy((char*)dt_node_tmp->dt_entry_m,(char*)cur_dt_entry, sizeof(struct dt_entry));
1328
1329 dprintf(SPEW, "Add DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1330 dt_node_tmp->dt_entry_m->platform_id, dt_node_tmp->dt_entry_m->variant_id,
1331 dt_node_tmp->dt_entry_m->board_hw_subtype, dt_node_tmp->dt_entry_m->soc_rev,
1332 dt_node_tmp->dt_entry_m->pmic_rev[0], dt_node_tmp->dt_entry_m->pmic_rev[1],
1333 dt_node_tmp->dt_entry_m->pmic_rev[2], dt_node_tmp->dt_entry_m->pmic_rev[3],
1334 dt_node_tmp->dt_entry_m->offset, dt_node_tmp->dt_entry_m->size);
1335
1336 insert_dt_entry_in_queue(dt_list, dt_node_tmp);
1337 return 1;
1338 }
1339 return 0;
1340}
1341
1342static int platform_dt_absolute_compat_match(struct dt_entry_node *dt_list, uint32_t dtb_info) {
1343 struct dt_entry_node *dt_node_tmp1 = NULL;
1344 struct dt_entry_node *dt_node_tmp2 = NULL;
1345 uint32_t current_info = 0;
1346 uint32_t board_info = 0;
1347 uint32_t best_info = 0;
1348 uint32_t current_pmic_model[4] = {0, 0, 0, 0};
1349 uint32_t board_pmic_model[4] = {0, 0, 0, 0};
1350 uint32_t best_pmic_model[4] = {0, 0, 0, 0};
1351 uint32_t delete_current_dt = 0;
1352 uint32_t i;
1353
1354 /* start to select the exact entry
1355 * default to exact match 0, if find current DTB entry info is the same as board info,
1356 * then exact match board info.
1357 */
1358 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1359 if (!dt_node_tmp1){
1360 dprintf(SPEW, "Current node is the end\n");
1361 break;
1362 }
1363 switch(dtb_info) {
1364 case DTB_FOUNDRY:
1365 current_info = ((dt_node_tmp1->dt_entry_m->platform_id) & 0x00ff0000);
Channagoud Kadabi4cffc272014-10-29 11:23:26 -07001366 board_info = board_foundry_id() << 16;
Lijuan Gao9f152862014-08-18 13:45:24 +08001367 break;
1368 case DTB_PMIC_MODEL:
1369 for (i = 0; i < 4; i++) {
1370 current_pmic_model[i] = (dt_node_tmp1->dt_entry_m->pmic_rev[i] & 0xff);
1371 board_pmic_model[i] = (board_pmic_target(i) & 0xff);
1372 }
1373 break;
Lijuan Gaof8e95722014-12-23 03:03:12 -05001374 case DTB_PANEL_TYPE:
1375 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0x1800);
1376 board_info = (target_get_hlos_subtype() & 0x1800);
1377 break;
1378 case DTB_BOOT_DEVICE:
1379 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0xf0000);
1380 board_info = (target_get_hlos_subtype() & 0xf0000);
1381 break;
Lijuan Gao9f152862014-08-18 13:45:24 +08001382 default:
1383 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
1384 dtb_info);
Maria Yuca51ee22013-06-27 21:45:24 +08001385 return 0;
Lijuan Gao9f152862014-08-18 13:45:24 +08001386 }
1387
1388 if (dtb_info == DTB_PMIC_MODEL) {
1389 if ((current_pmic_model[0] == board_pmic_model[0]) &&
1390 (current_pmic_model[1] == board_pmic_model[1]) &&
1391 (current_pmic_model[2] == board_pmic_model[2]) &&
1392 (current_pmic_model[3] == board_pmic_model[3])) {
1393
1394 for (i = 0; i < 4; i++) {
1395 best_pmic_model[i] = current_pmic_model[i];
1396 }
1397 break;
1398 }
1399 } else {
1400 if (current_info == board_info) {
1401 best_info = current_info;
1402 break;
1403 }
1404 }
1405 }
1406
1407 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1408 if (!dt_node_tmp1){
1409 dprintf(SPEW, "Current node is the end\n");
1410 break;
1411 }
1412 switch(dtb_info) {
1413 case DTB_FOUNDRY:
1414 current_info = ((dt_node_tmp1->dt_entry_m->platform_id) & 0x00ff0000);
1415 break;
1416 case DTB_PMIC_MODEL:
1417 for (i = 0; i < 4; i++) {
1418 current_pmic_model[i] = (dt_node_tmp1->dt_entry_m->pmic_rev[i] & 0xff);
1419 }
1420 break;
Lijuan Gaof8e95722014-12-23 03:03:12 -05001421 case DTB_PANEL_TYPE:
1422 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0x1800);
1423 break;
1424 case DTB_BOOT_DEVICE:
1425 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0xf0000);
1426 break;
Lijuan Gao9f152862014-08-18 13:45:24 +08001427 default:
1428 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
1429 dtb_info);
1430 return 0;
1431 }
1432
1433 if (dtb_info == DTB_PMIC_MODEL) {
1434 if ((current_pmic_model[0] != best_pmic_model[0]) ||
1435 (current_pmic_model[1] != best_pmic_model[1]) ||
1436 (current_pmic_model[2] != best_pmic_model[2]) ||
1437 (current_pmic_model[3] != best_pmic_model[3])) {
1438
1439 delete_current_dt = 1;
1440 }
1441 } else {
1442 if (current_info != best_info) {
1443 delete_current_dt = 1;
1444 }
1445 }
1446
1447 if (delete_current_dt) {
1448 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1449 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
1450 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
1451 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
1452 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
1453 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
1454
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001455 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001456 dt_entry_list_delete(dt_node_tmp1);
1457 dt_node_tmp1 = dt_node_tmp2;
1458 delete_current_dt = 0;
Maria Yuca51ee22013-06-27 21:45:24 +08001459 }
1460 }
Maria Yuca51ee22013-06-27 21:45:24 +08001461
Maria Yu2e2d2c22013-07-03 19:20:33 +08001462 return 1;
Maria Yuca51ee22013-06-27 21:45:24 +08001463}
1464
Lijuan Gao9f152862014-08-18 13:45:24 +08001465static int update_dtb_entry_node(struct dt_entry_node *dt_list, uint32_t dtb_info) {
1466 struct dt_entry_node *dt_node_tmp1 = NULL;
1467 struct dt_entry_node *dt_node_tmp2 = NULL;
1468 uint32_t current_info = 0;
1469 uint32_t board_info = 0;
1470 uint32_t best_info = 0;
1471
1472 /* start to select the best entry*/
1473 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1474 if (!dt_node_tmp1){
1475 dprintf(SPEW, "Current node is the end\n");
1476 break;
1477 }
1478 switch(dtb_info) {
1479 case DTB_SOC:
1480 current_info = dt_node_tmp1->dt_entry_m->soc_rev;
1481 board_info = board_soc_version();
1482 break;
1483 case DTB_MAJOR_MINOR:
1484 current_info = ((dt_node_tmp1->dt_entry_m->variant_id) & 0x00ffff00);
1485 board_info = (board_target_id() & 0x00ffff00);
1486 break;
1487 case DTB_PMIC0:
1488 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[0]) & 0x00ffff00);
1489 board_info = (board_pmic_target(0) & 0x00ffff00);
1490 break;
1491 case DTB_PMIC1:
1492 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[1]) & 0x00ffff00);
1493 board_info = (board_pmic_target(1) & 0x00ffff00);
1494 break;
1495 case DTB_PMIC2:
1496 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[2]) & 0x00ffff00);
1497 board_info = (board_pmic_target(2) & 0x00ffff00);
1498 break;
1499 case DTB_PMIC3:
1500 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[3]) & 0x00ffff00);
1501 board_info = (board_pmic_target(3) & 0x00ffff00);
1502 break;
1503 default:
1504 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
1505 dtb_info);
1506 return 0;
1507 }
1508
1509 if (current_info == board_info) {
1510 best_info = current_info;
1511 break;
1512 }
1513 if ((current_info < board_info) && (current_info > best_info)) {
1514 best_info = current_info;
1515 }
1516 if (current_info < best_info) {
1517 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1518 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
1519 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
1520 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
1521 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
1522 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
1523
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001524 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001525 dt_entry_list_delete(dt_node_tmp1);
1526 dt_node_tmp1 = dt_node_tmp2;
1527 }
1528 }
1529
1530 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1531 if (!dt_node_tmp1){
1532 dprintf(SPEW, "Current node is the end\n");
1533 break;
1534 }
1535 switch(dtb_info) {
1536 case DTB_SOC:
1537 current_info = dt_node_tmp1->dt_entry_m->soc_rev;
1538 break;
1539 case DTB_MAJOR_MINOR:
1540 current_info = ((dt_node_tmp1->dt_entry_m->variant_id) & 0x00ffff00);
1541 break;
1542 case DTB_PMIC0:
1543 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[0]) & 0x00ffff00);
1544 break;
1545 case DTB_PMIC1:
1546 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[1]) & 0x00ffff00);
1547 break;
1548 case DTB_PMIC2:
1549 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[2]) & 0x00ffff00);
1550 break;
1551 case DTB_PMIC3:
1552 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[3]) & 0x00ffff00);
1553 break;
1554 default:
1555 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
1556 dtb_info);
1557 return 0;
1558 }
1559
1560 if (current_info != best_info) {
1561 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1562 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
1563 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
1564 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
1565 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
1566 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
1567
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001568 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001569 dt_entry_list_delete(dt_node_tmp1);
1570 dt_node_tmp1 = dt_node_tmp2;
1571 }
1572 }
1573 return 1;
1574}
1575
1576static struct dt_entry *platform_dt_match_best(struct dt_entry_node *dt_list)
1577{
1578 struct dt_entry_node *dt_node_tmp1 = NULL;
1579
1580 /* check Foundry id
1581 * the foundry id must exact match board founddry id, this is compatibility check,
1582 * if couldn't find the exact match from DTB, will exact match 0x0.
1583 */
1584 if (!platform_dt_absolute_compat_match(dt_list, DTB_FOUNDRY))
1585 return NULL;
1586
1587 /* check PMIC model
1588 * the PMIC model must exact match board PMIC model, this is compatibility check,
1589 * if couldn't find the exact match from DTB, will exact match 0x0.
1590 */
1591 if (!platform_dt_absolute_compat_match(dt_list, DTB_PMIC_MODEL))
1592 return NULL;
1593
Lijuan Gaof8e95722014-12-23 03:03:12 -05001594 /* check panel type
1595 * the panel type must exact match board panel type, this is compatibility check,
1596 * if couldn't find the exact match from DTB, will exact match 0x0.
1597 */
1598 if (!platform_dt_absolute_compat_match(dt_list, DTB_PANEL_TYPE))
1599 return NULL;
1600
1601 /* check boot device subtype
1602 * the boot device subtype must exact match board boot device subtype, this is compatibility check,
1603 * if couldn't find the exact match from DTB, will exact match 0x0.
1604 */
1605 if (!platform_dt_absolute_compat_match(dt_list, DTB_BOOT_DEVICE))
1606 return NULL;
1607
Lijuan Gao9f152862014-08-18 13:45:24 +08001608 /* check soc version
1609 * the suitable soc version must less than or equal to board soc version
1610 */
1611 if (!update_dtb_entry_node(dt_list, DTB_SOC))
1612 return NULL;
1613
1614 /*check major and minor version
1615 * the suitable major&minor version must less than or equal to board major&minor version
1616 */
1617 if (!update_dtb_entry_node(dt_list, DTB_MAJOR_MINOR))
1618 return NULL;
1619
1620 /*check pmic info
1621 * the suitable pmic major&minor info must less than or equal to board pmic major&minor version
1622 */
1623 if (!update_dtb_entry_node(dt_list, DTB_PMIC0))
1624 return NULL;
1625 if (!update_dtb_entry_node(dt_list, DTB_PMIC1))
1626 return NULL;
1627 if (!update_dtb_entry_node(dt_list, DTB_PMIC2))
1628 return NULL;
1629 if (!update_dtb_entry_node(dt_list, DTB_PMIC3))
1630 return NULL;
1631
1632 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1633 if (!dt_node_tmp1) {
1634 dprintf(CRITICAL, "ERROR: Couldn't find the suitable DTB!\n");
1635 return NULL;
1636 }
1637 if (dt_node_tmp1->dt_entry_m)
1638 return dt_node_tmp1->dt_entry_m;
1639 }
1640
1641 return NULL;
1642}
1643
1644/* Function to obtain the index information for the correct device tree
1645 * based on the platform data.
1646 * If a matching device tree is found, the information is returned in the
1647 * "dt_entry_info" out parameter and a function value of 0 is returned, otherwise
1648 * a non-zero function value is returned.
1649 */
1650int dev_tree_get_entry_info(struct dt_table *table, struct dt_entry *dt_entry_info)
Maria Yuca51ee22013-06-27 21:45:24 +08001651{
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001652 uint32_t i;
Lijuan Gao9f152862014-08-18 13:45:24 +08001653 unsigned char *table_ptr = NULL;
Joel Kingaa335dc2013-06-03 16:11:08 -07001654 struct dt_entry dt_entry_buf_1;
Lijuan Gao9f152862014-08-18 13:45:24 +08001655 struct dt_entry *cur_dt_entry = NULL;
1656 struct dt_entry *best_match_dt_entry = NULL;
1657 struct dt_entry_v1 *dt_entry_v1 = NULL;
1658 struct dt_entry_v2 *dt_entry_v2 = NULL;
1659 struct dt_entry_node *dt_entry_queue = NULL;
1660 struct dt_entry_node *dt_node_tmp1 = NULL;
1661 struct dt_entry_node *dt_node_tmp2 = NULL;
Maria Yu2e2d2c22013-07-03 19:20:33 +08001662 uint32_t found = 0;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001663
Joel Kingaa335dc2013-06-03 16:11:08 -07001664 if (!dt_entry_info) {
1665 dprintf(CRITICAL, "ERROR: Bad parameter passed to %s \n",
1666 __func__);
1667 return -1;
1668 }
1669
1670 table_ptr = (unsigned char *)table + DEV_TREE_HEADER_SIZE;
1671 cur_dt_entry = &dt_entry_buf_1;
1672 best_match_dt_entry = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +08001673 dt_entry_queue = (struct dt_entry_node *)
1674 malloc(sizeof(struct dt_entry_node));
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001675
Lijuan Gao9f152862014-08-18 13:45:24 +08001676 if (!dt_entry_queue) {
1677 dprintf(CRITICAL, "Out of memory\n");
1678 return -1;
1679 }
1680
1681 list_initialize(&dt_entry_queue->node);
1682 dprintf(INFO, "DTB Total entry: %d, DTB version: %d\n", table->num_entries, table->version);
Maria Yu2e2d2c22013-07-03 19:20:33 +08001683 for(i = 0; found == 0 && i < table->num_entries; i++)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001684 {
Joel Kingaa335dc2013-06-03 16:11:08 -07001685 memset(cur_dt_entry, 0, sizeof(struct dt_entry));
1686 switch(table->version) {
1687 case DEV_TREE_VERSION_V1:
1688 dt_entry_v1 = (struct dt_entry_v1 *)table_ptr;
1689 cur_dt_entry->platform_id = dt_entry_v1->platform_id;
1690 cur_dt_entry->variant_id = dt_entry_v1->variant_id;
1691 cur_dt_entry->soc_rev = dt_entry_v1->soc_rev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001692 cur_dt_entry->board_hw_subtype = (dt_entry_v1->variant_id >> 0x18);
1693 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
1694 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
1695 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
1696 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
Joel Kingaa335dc2013-06-03 16:11:08 -07001697 cur_dt_entry->offset = dt_entry_v1->offset;
1698 cur_dt_entry->size = dt_entry_v1->size;
1699 table_ptr += sizeof(struct dt_entry_v1);
1700 break;
1701 case DEV_TREE_VERSION_V2:
Lijuan Gao9f152862014-08-18 13:45:24 +08001702 dt_entry_v2 = (struct dt_entry_v2*)table_ptr;
1703 cur_dt_entry->platform_id = dt_entry_v2->platform_id;
1704 cur_dt_entry->variant_id = dt_entry_v2->variant_id;
1705 cur_dt_entry->soc_rev = dt_entry_v2->soc_rev;
1706 /* For V2 version of DTBs we have platform version field as part
1707 * of variant ID, in such case the subtype will be mentioned as 0x0
1708 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
1709 * SS -- Subtype
1710 * PM -- Platform major version
1711 * Pm -- Platform minor version
1712 * PH -- Platform hardware CDP/MTP
1713 * In such case to make it compatible with LK algorithm move the subtype
1714 * from variant_id to subtype field
1715 */
1716 if (dt_entry_v2->board_hw_subtype == 0)
1717 cur_dt_entry->board_hw_subtype = (cur_dt_entry->variant_id >> 0x18);
1718 else
1719 cur_dt_entry->board_hw_subtype = dt_entry_v2->board_hw_subtype;
1720 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
1721 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
1722 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
1723 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
1724 cur_dt_entry->offset = dt_entry_v2->offset;
1725 cur_dt_entry->size = dt_entry_v2->size;
1726 table_ptr += sizeof(struct dt_entry_v2);
1727 break;
1728 case DEV_TREE_VERSION_V3:
Joel Kingaa335dc2013-06-03 16:11:08 -07001729 memcpy(cur_dt_entry, (struct dt_entry *)table_ptr,
1730 sizeof(struct dt_entry));
Lijuan Gao9f152862014-08-18 13:45:24 +08001731 /* For V3 version of DTBs we have platform version field as part
1732 * of variant ID, in such case the subtype will be mentioned as 0x0
1733 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
1734 * SS -- Subtype
1735 * PM -- Platform major version
1736 * Pm -- Platform minor version
1737 * PH -- Platform hardware CDP/MTP
1738 * In such case to make it compatible with LK algorithm move the subtype
1739 * from variant_id to subtype field
1740 */
1741 if (cur_dt_entry->board_hw_subtype == 0)
1742 cur_dt_entry->board_hw_subtype = (cur_dt_entry->variant_id >> 0x18);
1743
Joel Kingaa335dc2013-06-03 16:11:08 -07001744 table_ptr += sizeof(struct dt_entry);
1745 break;
1746 default:
1747 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
1748 table->version);
Lijuan Gao9f152862014-08-18 13:45:24 +08001749 free(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001750 return -1;
1751 }
1752
Lijuan Gao9f152862014-08-18 13:45:24 +08001753 /* DTBs must match the platform_id, platform_hw_id, platform_subtype and DDR size.
1754 * The satisfactory DTBs are stored in dt_entry_queue
1755 */
1756 platform_dt_absolute_match(cur_dt_entry, dt_entry_queue);
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -08001757
Lijuan Gao9f152862014-08-18 13:45:24 +08001758 }
1759 best_match_dt_entry = platform_dt_match_best(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001760 if (best_match_dt_entry) {
1761 *dt_entry_info = *best_match_dt_entry;
Maria Yu2e2d2c22013-07-03 19:20:33 +08001762 found = 1;
1763 }
1764
1765 if (found != 0) {
Sundarajan Srinivasan763c0db2014-05-20 17:08:36 -07001766 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 -07001767 dt_entry_info->platform_id, dt_entry_info->soc_rev,
1768 dt_entry_info->variant_id, dt_entry_info->board_hw_subtype,
Lijuan Gao9f152862014-08-18 13:45:24 +08001769 board_platform_id(), board_soc_version(),
1770 board_target_id(), board_hardware_subtype());
1771 if (dt_entry_info->pmic_rev[0] == 0 && dt_entry_info->pmic_rev[0] == 0 &&
1772 dt_entry_info->pmic_rev[0] == 0 && dt_entry_info->pmic_rev[0] == 0) {
1773 dprintf(SPEW, "No maintain pmic info in DTB, device pmic info is 0x%0x/0x%x/0x%x/0x%0x\n",
1774 board_pmic_target(0), board_pmic_target(1),
1775 board_pmic_target(2), board_pmic_target(3));
1776 } else {
1777 dprintf(INFO, "Using pmic info 0x%0x/0x%x/0x%x/0x%0x for device 0x%0x/0x%x/0x%x/0x%0x\n",
1778 dt_entry_info->pmic_rev[0], dt_entry_info->pmic_rev[1],
1779 dt_entry_info->pmic_rev[2], dt_entry_info->pmic_rev[3],
1780 board_pmic_target(0), board_pmic_target(1),
1781 board_pmic_target(2), board_pmic_target(3));
1782 }
Joel Kingaa335dc2013-06-03 16:11:08 -07001783 return 0;
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -08001784 }
1785
Lijuan Gao9f152862014-08-18 13:45:24 +08001786 dprintf(CRITICAL, "ERROR: Unable to find suitable device tree for device (%u/0x%08x/0x%08x/%u)\n",
1787 board_platform_id(), board_soc_version(),
1788 board_target_id(), board_hardware_subtype());
1789
1790 list_for_every_entry(&dt_entry_queue->node, dt_node_tmp1, dt_node, node) {
1791 /* free node memory */
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001792 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001793 dt_entry_list_delete(dt_node_tmp1);
1794 dt_node_tmp1 = dt_node_tmp2;
1795 }
1796 free(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001797 return -1;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001798}
1799
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001800/* Function to add the first RAM partition info to the device tree.
1801 * Note: The function replaces the reg property in the "/memory" node
1802 * with the addr and size provided.
1803 */
1804int dev_tree_add_first_mem_info(uint32_t *fdt, uint32_t offset, uint32_t addr, uint32_t size)
1805{
1806 int ret;
1807
1808 ret = fdt_setprop_u32(fdt, offset, "reg", addr);
1809
1810 if (ret)
1811 {
1812 dprintf(CRITICAL, "Failed to add the memory information addr: %d\n",
1813 ret);
1814 }
1815
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001816 ret = fdt_appendprop_u32(fdt, offset, "reg", size);
1817
1818 if (ret)
1819 {
1820 dprintf(CRITICAL, "Failed to add the memory information size: %d\n",
1821 ret);
1822 }
1823
1824 return ret;
1825}
1826
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001827static 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 -07001828{
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001829 int len;
1830 uint32_t *valp;
1831 int ret;
1832 uint32_t offset;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001833
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001834 mem_node->offset = mem_node_offset;
1835
1836 /* Get offset of the root node */
1837 ret = fdt_path_offset(fdt, "/");
1838 if (ret < 0)
1839 {
1840 dprintf(CRITICAL, "Could not find memory node.\n");
1841 return ret;
1842 }
1843
1844 offset = ret;
1845
1846 /* Find the #address-cells size. */
1847 valp = (uint32_t*)fdt_getprop(fdt, offset, "#address-cells", &len);
Lijuan Gaoae0927b2014-07-18 17:16:16 +08001848 if (len <= 0 || !valp)
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001849 {
1850 if (len == -FDT_ERR_NOTFOUND)
1851 {
1852 /* Property not found.
1853 * Assume standard sizes.
1854 */
1855 mem_node->addr_cell_size = 2;
1856 dprintf(CRITICAL, "Using default #addr_cell_size: %u\n", mem_node->addr_cell_size);
1857 }
1858 else
1859 {
1860 dprintf(CRITICAL, "Error finding the #address-cells property\n");
1861 return len;
1862 }
1863 }
1864 else
1865 mem_node->addr_cell_size = fdt32_to_cpu(*valp);
1866
1867 /* Find the #size-cells size. */
1868 valp = (uint32_t*)fdt_getprop(fdt, offset, "#size-cells", &len);
Lijuan Gaoae0927b2014-07-18 17:16:16 +08001869 if (len <= 0 || !valp)
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001870 {
1871 if (len == -FDT_ERR_NOTFOUND)
1872 {
1873 /* Property not found.
1874 * Assume standard sizes.
1875 */
1876 mem_node->size_cell_size = 1;
1877 dprintf(CRITICAL, "Using default #size_cell_size: %u\n", mem_node->size_cell_size);
1878 }
1879 else
1880 {
1881 dprintf(CRITICAL, "Error finding the #size-cells property\n");
1882 return len;
1883 }
1884 }
1885 else
1886 mem_node->size_cell_size = fdt32_to_cpu(*valp);
1887
1888 return 0;
1889}
1890
1891static void dev_tree_update_memory_node(uint32_t offset)
1892{
1893 mem_node.offset = offset;
1894 mem_node.addr_cell_size = 1;
1895 mem_node.size_cell_size = 1;
1896}
1897
1898/* Function to add the subsequent RAM partition info to the device tree. */
1899int dev_tree_add_mem_info(void *fdt, uint32_t offset, uint64_t addr, uint64_t size)
1900{
1901 int ret = 0;
1902
1903 if(smem_get_ram_ptable_version() >= 1)
1904 {
1905 ret = dev_tree_query_memory_cell_sizes(fdt, &mem_node, offset);
1906 if (ret < 0)
1907 {
1908 dprintf(CRITICAL, "Could not find #address-cells and #size-cells properties: ret %d\n", ret);
1909 return ret;
1910 }
1911
1912 }
1913 else
1914 {
1915 dev_tree_update_memory_node(offset);
1916 }
1917
1918 if (!(mem_node.mem_info_cnt))
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001919 {
1920 /* Replace any other reg prop in the memory node. */
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001921
1922 /* cell_size is the number of 32 bit words used to represent an address/length in the device tree.
1923 * memory node in DT can be either 32-bit(cell-size = 1) or 64-bit(cell-size = 2).So when updating
1924 * the memory node in the device tree, we write one word or two words based on cell_size = 1 or 2.
1925 */
1926
1927 if(mem_node.addr_cell_size == 2)
1928 {
1929 ret = fdt_setprop_u32(fdt, mem_node.offset, "reg", addr >> 32);
1930 if(ret)
1931 {
1932 dprintf(CRITICAL, "ERROR: Could not set prop reg for memory node\n");
1933 return ret;
1934 }
1935
1936 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1937 if(ret)
1938 {
1939 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1940 return ret;
1941 }
1942 }
1943 else
1944 {
1945 ret = fdt_setprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1946 if(ret)
1947 {
1948 dprintf(CRITICAL, "ERROR: Could not set prop reg for memory node\n");
1949 return ret;
1950 }
1951 }
1952
1953 mem_node.mem_info_cnt = 1;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001954 }
1955 else
1956 {
1957 /* Append the mem info to the reg prop for subsequent nodes. */
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001958 if(mem_node.addr_cell_size == 2)
1959 {
1960 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", addr >> 32);
1961 if(ret)
1962 {
1963 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1964 return ret;
1965 }
1966 }
1967
1968 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1969 if(ret)
1970 {
1971 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1972 return ret;
1973 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001974 }
1975
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001976 if(mem_node.size_cell_size == 2)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001977 {
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001978 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", size>>32);
1979 if(ret)
1980 {
1981 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1982 return ret;
1983 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001984 }
1985
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001986 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)size);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001987
1988 if (ret)
1989 {
1990 dprintf(CRITICAL, "Failed to add the memory information size: %d\n",
1991 ret);
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001992 return ret;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001993 }
1994
1995 return ret;
1996}
1997
1998/* Top level function that updates the device tree. */
1999int update_device_tree(void *fdt, const char *cmdline,
2000 void *ramdisk, uint32_t ramdisk_size)
2001{
2002 int ret = 0;
2003 uint32_t offset;
lijuangc76a7632017-12-07 14:37:56 +08002004#if ENABLE_KASLRSEED_SUPPORT
lijuang0ac31232018-10-19 17:53:36 +08002005 uint64_t kaslrseed;
lijuangc76a7632017-12-07 14:37:56 +08002006#endif
Mayank Grover2533aab2018-02-23 18:06:07 +05302007 uint32_t cmdline_len = 0;
2008
2009 if (cmdline)
2010 cmdline_len = strlen(cmdline);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002011
2012 /* Check the device tree header */
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +05302013 ret = fdt_check_header(fdt) || fdt_check_header_ext(fdt);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002014 if (ret)
2015 {
2016 dprintf(CRITICAL, "Invalid device tree header \n");
2017 return ret;
2018 }
2019
P.V. Phani Kumar9cd95102016-03-09 12:35:23 +05302020 if (check_aboot_addr_range_overlap((uint32_t)fdt,
Mayank Grover2533aab2018-02-23 18:06:07 +05302021 (fdt_totalsize(fdt) + DTB_PAD_SIZE + cmdline_len))) {
P.V. Phani Kumar9cd95102016-03-09 12:35:23 +05302022 dprintf(CRITICAL, "Error: Fdt addresses overlap with aboot addresses.\n");
2023 return ret;
2024 }
2025
Deepa Dinamani1c970732013-04-19 14:23:01 -07002026 /* Add padding to make space for new nodes and properties. */
Mayank Grover2533aab2018-02-23 18:06:07 +05302027 ret = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + DTB_PAD_SIZE + cmdline_len);
Deepa Dinamani1c970732013-04-19 14:23:01 -07002028 if (ret!= 0)
2029 {
2030 dprintf(CRITICAL, "Failed to move/resize dtb buffer: %d\n", ret);
2031 return ret;
2032 }
2033
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002034 /* Get offset of the memory node */
2035 ret = fdt_path_offset(fdt, "/memory");
2036 if (ret < 0)
2037 {
2038 dprintf(CRITICAL, "Could not find memory node.\n");
2039 return ret;
2040 }
2041
2042 offset = ret;
2043
2044 ret = target_dev_tree_mem(fdt, offset);
2045 if(ret)
2046 {
2047 dprintf(CRITICAL, "ERROR: Cannot update memory node\n");
2048 return ret;
2049 }
2050
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002051 /* Get offset of the chosen node */
2052 ret = fdt_path_offset(fdt, "/chosen");
2053 if (ret < 0)
2054 {
2055 dprintf(CRITICAL, "Could not find chosen node.\n");
2056 return ret;
2057 }
2058
2059 offset = ret;
Maria Yuabde9542014-07-07 14:49:34 +08002060 if (cmdline)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002061 {
Maria Yuabde9542014-07-07 14:49:34 +08002062 /* Adding the cmdline to the chosen node */
2063 ret = fdt_appendprop_string(fdt, offset, (const char*)"bootargs", (const void*)cmdline);
2064 if (ret)
2065 {
2066 dprintf(CRITICAL, "ERROR: Cannot update chosen node [bootargs]\n");
2067 return ret;
2068 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002069 }
2070
lijuangc76a7632017-12-07 14:37:56 +08002071#if ENABLE_KASLRSEED_SUPPORT
lijuang0ac31232018-10-19 17:53:36 +08002072 if (!scm_random((uintptr_t *)&kaslrseed, sizeof(kaslrseed))) {
lijuangc76a7632017-12-07 14:37:56 +08002073 /* Adding Kaslr Seed to the chosen node */
2074 ret = fdt_appendprop_u64 (fdt, offset, (const char *)"kaslr-seed", (uint64_t)kaslrseed);
2075 if (ret)
2076 dprintf(CRITICAL, "ERROR: Cannot update chosen node [kaslr-seed] - 0x%x\n", ret);
2077 else
2078 dprintf(CRITICAL, "kaslr-Seed is added to chosen node\n");
2079 } else {
2080 dprintf(CRITICAL, "ERROR: Cannot generate Kaslr Seed\n");
2081 }
2082#endif
2083
Joonwoo Parka5b5f492014-02-13 18:24:48 -08002084 if (ramdisk_size) {
2085 /* Adding the initrd-start to the chosen node */
2086 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-start",
2087 (uint32_t)ramdisk);
2088 if (ret)
2089 {
2090 dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-start]\n");
2091 return ret;
2092 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002093
Joonwoo Parka5b5f492014-02-13 18:24:48 -08002094 /* Adding the initrd-end to the chosen node */
2095 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-end",
2096 ((uint32_t)ramdisk + ramdisk_size));
2097 if (ret)
2098 {
2099 dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-end]\n");
2100 return ret;
2101 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002102 }
2103
Kishor PK536904a2017-07-13 17:18:59 +05302104#if ENABLE_BOOTDEVICE_MOUNT
2105 /* Update fstab node */
2106 dprintf(SPEW, "Start of fstab node update:%zu ms\n", platform_get_sclk_count());
2107 if (update_fstab_node(fdt) != 0) {
2108 dprintf(CRITICAL, "ERROR: Cannot update fstab node\n");
2109 return ret;
2110 }
2111 dprintf(SPEW, "End of fstab node update:%zu ms\n", platform_get_sclk_count());
2112#endif
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002113 fdt_pack(fdt);
2114
Channagoud Kadabiffaea422014-12-05 15:45:41 -08002115#if ENABLE_PARTIAL_GOODS_SUPPORT
2116 update_partial_goods_dtb_nodes(fdt);
2117#endif
2118
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002119 return ret;
2120}
Kishor PK536904a2017-07-13 17:18:59 +05302121
2122#if ENABLE_BOOTDEVICE_MOUNT
2123/*Update device tree for fstab node */
2124static int update_fstab_node(void *fdt)
2125{
2126 int ret = 0;
2127 int str_len = 0;
2128 int parent_offset = 0;
2129 int subnode_offset = 0;
2130 int prop_length = 0;
2131 int prefix_string_len = 0;
2132 char *node_name = NULL;
2133 char *boot_dev_buf = NULL;
2134 char *new_str = NULL;
2135 char *prefix_str = NULL;
2136 char *suffix_str = NULL;
2137 const struct fdt_property *prop = NULL;
2138
2139 /* Find the parent node */
2140 parent_offset = fdt_path_offset(fdt, fstab_table.parent_node);
2141 if (parent_offset < 0) {
2142 dprintf(CRITICAL, "Failed to get parent node: fstab error: %d\n", parent_offset);
2143 return -1;
2144 }
2145 dprintf(SPEW, "Node: %s found.\n", fdt_get_name(fdt, parent_offset, NULL));
2146
2147 /* Get boot device type */
2148 boot_dev_buf = (char *) malloc(sizeof(char) * BOOT_DEV_MAX_LEN);
2149 if (!boot_dev_buf) {
2150 dprintf(CRITICAL, "Failed to allocate memory for boot device\n");
2151 return -1;
2152 }
2153
2154 new_str = (char *) malloc(sizeof(char) * NODE_PROPERTY_MAX_LEN);
2155 if (!new_str) {
2156 dprintf(CRITICAL, "Failed to allocate memory for node property string\n");
2157 return -1;
2158 }
2159
2160
2161 platform_boot_dev_cmdline(boot_dev_buf);
2162
2163 /* Get properties of all sub nodes */
2164 for (subnode_offset = fdt_first_subnode(fdt, parent_offset); subnode_offset >= 0; subnode_offset = fdt_next_subnode(fdt, subnode_offset)) {
2165 prop = fdt_get_property(fdt, subnode_offset, fstab_table.node_prop, &prop_length);
2166 node_name = (char *)(uintptr_t)fdt_get_name(fdt, subnode_offset, NULL);
2167 if (!prop) {
2168 dprintf(CRITICAL, "Property:%s is not found for sub node:%s\n", fstab_table.node_prop, node_name);
2169 } else {
2170 dprintf(CRITICAL, "Property:%s found for sub node:%s\tproperty:%s\n", fstab_table.node_prop, node_name, prop->data);
2171 /* Pointer to fdt 'dev' property string that needs to update based on the 'androidboot.bootdevice' */
2172 memset(new_str, 0, NODE_PROPERTY_MAX_LEN);
2173 prefix_str = (char *)prop->data;
2174 if (strlen(prefix_str) > NODE_PROPERTY_MAX_LEN) {
2175 dprintf(CRITICAL, "Property string length is greater than node property max length\n");
2176 continue;
2177 }
2178 suffix_str = strstr(prefix_str, fstab_table.device_path_id);
2179 if (!suffix_str) {
2180 dprintf(CRITICAL, "Property is not proper to update\n");
2181 continue;
2182 }
2183 suffix_str += strlen(fstab_table.device_path_id);
2184 prefix_string_len = strlen(prefix_str) - (strlen(suffix_str) - 1);
2185 suffix_str = strstr((suffix_str + 1), "/");
2186 str_len = strlcpy(new_str, prefix_str, prefix_string_len);
2187 if (!str_len) {
2188 dprintf(CRITICAL, "Property length is not proper to update\n");
2189 continue;
2190 }
2191 str_len = strlcat(new_str, boot_dev_buf, strlen(prefix_str));
2192 if (!str_len) {
2193 dprintf(CRITICAL, "Property length is not proper to update\n");
2194 continue;
2195 }
2196 str_len = strlcat(new_str, suffix_str, strlen(prefix_str));
2197 if (!str_len) {
2198 dprintf(CRITICAL, "Property length is not proper to update\n");
2199 continue;
2200 }
2201 /* Update the new property in the memory */
2202 memscpy(prefix_str, strlen(prefix_str), new_str, strlen(new_str) + 1);
2203 /* Update the property with new value */
2204 ret = fdt_setprop(fdt, subnode_offset, fstab_table.node_prop, (const void *)prefix_str, strlen(prefix_str) + 1);
2205 if(ret) {
2206 dprintf(CRITICAL, "Failed to update the node with new property\n");
2207 continue;
2208 }
2209 dprintf(CRITICAL, "Updated %s with new property %s\n", node_name, prop->data);
2210 }
2211 }
2212 if (boot_dev_buf)
2213 free(boot_dev_buf);
2214 if (new_str)
2215 free(new_str);
2216 return ret;
2217}
2218#endif