blob: 2df16f0066293a0a0f542d48dd4efc824991d15f [file] [log] [blame]
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301/* Copyright (c) 2012-2015,2017-2018 The Linux Foundation. All rights reserved.
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27*/
28
29#include <libfdt.h>
30#include <dev_tree.h>
31#include <lib/ptable.h>
32#include <malloc.h>
33#include <qpic_nand.h>
34#include <stdlib.h>
35#include <string.h>
36#include <platform.h>
37#include <board.h>
Lijuan Gao9f152862014-08-18 13:45:24 +080038#include <list.h>
39#include <kernel/thread.h>
Mayank Grover1b6da5d2017-12-19 16:05:46 +053040#include <kernel/event.h>
vijay kumar4f4405f2014-08-08 11:49:53 +053041#include <target.h>
Channagoud Kadabiffaea422014-12-05 15:45:41 -080042#include <partial_goods.h>
Kishor PK536904a2017-07-13 17:18:59 +053043#include <boot_device.h>
44#include <platform.h>
lijuangc76a7632017-12-07 14:37:56 +080045#include <scm.h>
Mayank Grover1b6da5d2017-12-19 16:05:46 +053046#include <partition_parser.h>
47#include <libufdt_sysdeps.h>
48#include <ufdt_overlay.h>
Mayank Grover302432a2017-12-08 17:18:58 +053049#include <boot_stats.h>
Mayank Grover8f46a892018-09-10 13:24:59 +053050#include <verifiedboot.h>
Kishor PK536904a2017-07-13 17:18:59 +053051
52#define BOOT_DEV_MAX_LEN 64
53#define NODE_PROPERTY_MAX_LEN 64
Mayank Grover1b6da5d2017-12-19 16:05:46 +053054#define ADD_OF(a, b) (UINT_MAX - b > a) ? (a + b) : UINT_MAX
55#define ADDR_ALIGNMENT 16
56/** 512KB stack **/
57#define DTBO_STACK_SIZE (524288)
58#define MAX_DTBO_SZ 2097152
59
60static bool dtbo_needed = true;
61static void *board_dtb = NULL;
62static void *soc_dtb = NULL;
63static void *soc_dtb_hdr = NULL;
64static void *final_dtb_hdr = NULL;
65static event_t dtbo_event;
66
Mayank Grover1b6da5d2017-12-19 16:05:46 +053067dtbo_error ret = DTBO_SUCCESS;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -070068
Joel Kingaa335dc2013-06-03 16:11:08 -070069struct dt_entry_v1
70{
71 uint32_t platform_id;
72 uint32_t variant_id;
73 uint32_t soc_rev;
74 uint32_t offset;
75 uint32_t size;
76};
77
Kishor PK536904a2017-07-13 17:18:59 +053078#if ENABLE_BOOTDEVICE_MOUNT
79/* Look up table for fstab node */
80struct fstab_node
81{
82 const char *parent_node;
83 const char *node_prop;
84 const char *device_path_id;
85};
86
87static struct fstab_node fstab_table =
88{
89 "/firmware/android/fstab", "dev", "/soc/"
90};
91#endif
92
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -070093static struct dt_mem_node_info mem_node;
Lijuan Gao9f152862014-08-18 13:45:24 +080094static int platform_dt_absolute_match(struct dt_entry *cur_dt_entry, struct dt_entry_node *dt_list);
95static struct dt_entry *platform_dt_match_best(struct dt_entry_node *dt_list);
96static int update_dtb_entry_node(struct dt_entry_node *dt_list, uint32_t dtb_info);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -070097extern int target_is_emmc_boot(void);
98extern uint32_t target_dev_tree_mem(void *fdt, uint32_t memory_node_offset);
Kishor PK536904a2017-07-13 17:18:59 +053099static int update_fstab_node(void *fdt);
100
Deepa Dinamanic55f01b2013-05-30 14:05:56 -0700101/* TODO: This function needs to be moved to target layer to check violations
102 * against all the other regions as well.
103 */
Vijay Kumar Pendoti9c002ad2016-03-09 13:52:45 +0530104extern int check_aboot_addr_range_overlap(uintptr_t start, uint32_t size);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700105
lijuang0cce8bf2018-08-23 10:56:42 +0800106static int dtbo_idx = INVALID_PTN;
107int get_dtbo_idx (void)
108{
109 return dtbo_idx;
110}
111
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +0530112int fdt_check_header_ext(const void *fdt)
113{
114 uintptr_t fdt_start, fdt_end;
115 fdt_start = (uintptr_t)fdt;
116 if(fdt_start + fdt_totalsize(fdt) < fdt_start)
117 {
118 dprintf(CRITICAL,"Integer over in fdt header %s\t%d",__func__,__LINE__);
119 return FDT_ERR_BADOFFSET;
120 }
121 fdt_end = fdt_start + fdt_totalsize(fdt);
122
123 if (((uint64_t)fdt_start + (uint64_t)fdt_off_dt_struct(fdt) + (uint64_t)fdt_size_dt_struct(fdt)) > UINT_MAX)
124 return FDT_ERR_BADOFFSET;
125
126 if ((fdt_start + fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt)) > fdt_end)
127 return FDT_ERR_BADOFFSET;
128
129 if (((uint64_t)fdt_start + (uint64_t)fdt_off_dt_strings(fdt) + (uint64_t)fdt_size_dt_strings(fdt)) > UINT_MAX)
130 return FDT_ERR_BADOFFSET;
131
132 if ((fdt_start + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)) > fdt_end)
133 return FDT_ERR_BADOFFSET;
134
135 return 0;
136}
137
Shashank Mittalc0f10282013-07-15 14:53:31 -0700138/* Returns soc version if platform id and hardware id matches
139 otherwise return 0xFFFFFFFF */
140#define INVALID_SOC_REV_ID 0XFFFFFFFF
Lijuan Gao9f152862014-08-18 13:45:24 +0800141
142/* Add function to allocate dt entry list, used for recording
143* the entry which conform to platform_dt_absolute_match()
144*/
145static struct dt_entry_node *dt_entry_list_init(void)
146{
147 struct dt_entry_node *dt_node_member = NULL;
148
149 dt_node_member = (struct dt_entry_node *)
150 malloc(sizeof(struct dt_entry_node));
151
152 ASSERT(dt_node_member);
153
154 list_clear_node(&dt_node_member->node);
155 dt_node_member->dt_entry_m = (struct dt_entry *)
156 malloc(sizeof(struct dt_entry));
157 ASSERT(dt_node_member->dt_entry_m);
158
159 memset(dt_node_member->dt_entry_m ,0 ,sizeof(struct dt_entry));
160 return dt_node_member;
161}
162
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530163/*
164 * Function to validate dtbo image.
165 * return: TRUE or FALSE.
166 */
Mayank Groverb61c0c22018-09-04 15:09:32 +0530167dtbo_error load_validate_dtbo_image(void **dtbo_buf, uint32_t *dtbo_image_sz)
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530168{
169 uint64_t dtbo_total_size = 0;
Mayank Groverb61c0c22018-09-04 15:09:32 +0530170 static void *dtbo_image_buf = NULL;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530171 unsigned int dtbo_image_buf_size;
172 unsigned int dtbo_partition_size;
Mayank Groverb61c0c22018-09-04 15:09:32 +0530173 unsigned long long ptn, boot_img_sz;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530174 int index = INVALID_PTN;
175 int page_size = mmc_page_size();
176 struct dtbo_table_hdr *dtbo_table_header = NULL;
177 dtbo_error ret = DTBO_SUCCESS;
Mayank Groverb61c0c22018-09-04 15:09:32 +0530178 static bool dtbo_loaded = false;
179 static unsigned long long ptn_size = 0;
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530180 uint32_t recovery_dtbo_size = 0;
181 void *recovery_appended_dtbo = NULL;
Mayank Groverb61c0c22018-09-04 15:09:32 +0530182
183 /* If dtbo loaded skip loading */
184 if (dtbo_loaded)
185 goto out;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530186
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530187 get_recovery_dtbo_info(&recovery_dtbo_size, &recovery_appended_dtbo);
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530188
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530189 /* Intialize dtbo for recovery header v1 */
190 if (recovery_dtbo_size && recovery_appended_dtbo) {
191 dtbo_image_buf = recovery_appended_dtbo;
192 dtbo_partition_size = recovery_dtbo_size;
193 ptn_size = recovery_dtbo_size;
194 } else {
195 index = partition_get_index("dtbo");
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530196
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530197
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530198 /* Immediately return if dtbo is not supported */
199 if (index == INVALID_PTN)
200 {
201 ret = DTBO_NOT_SUPPORTED;
202 goto out;
203 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530204
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530205 ptn = partition_get_offset(index);
206 if(!ptn)
207 {
208 dprintf(CRITICAL, "ERROR: dtbo parition failed to get offset. \n");
209 ret = DTBO_ERROR;
210 goto out;
211 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530212
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530213 ptn_size = partition_get_size(index);
214 if (ptn_size > MAX_SUPPORTED_DTBO_IMG_BUF)
215 {
216 dprintf(CRITICAL, "ERROR: dtbo parition size is greater than supported.\n");
217 ret = DTBO_ERROR;
218 goto out;
219 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530220
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530221 /*
222 Read dtbo image into scratch region after kernel image.
223 dtbo_image_buf_size = total_scratch_region_size - boot_img_sz
224 */
225 boot_img_sz = partition_get_size(partition_get_index("boot"));
226 if (!boot_img_sz)
227 {
228 dprintf(CRITICAL, "ERROR: Unable to get boot partition size\n");
229 ret = DTBO_NOT_SUPPORTED;
230 goto out;
231 }
232
233 dtbo_image_buf_size = target_get_max_flash_size() - boot_img_sz;
234 dtbo_partition_size = ptn_size + ADDR_ALIGNMENT;
235 dtbo_partition_size = ROUND_TO_PAGE(dtbo_partition_size, (page_size - 1)); /* Maximum dtbo size possible */
236 if (dtbo_partition_size == UINT_MAX ||
237 dtbo_image_buf_size < dtbo_partition_size)
238 {
239 dprintf(CRITICAL, "ERROR: Invalid DTBO partition size\n");
240 ret = DTBO_NOT_SUPPORTED;
241 goto out;
242 }
243
244 mmc_set_lun(partition_get_lun(index));
245 /* read dtbo at last 10MB of scratch */
246 dtbo_image_buf = target_get_scratch_address() +
247 (target_get_max_flash_size() - DTBO_IMG_BUF);
248 dtbo_image_buf =
Mayank Grover8f46a892018-09-10 13:24:59 +0530249 (void *)ROUND_TO_PAGE((addr_t)dtbo_image_buf, (ADDR_ALIGNMENT-1));
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530250 if(dtbo_image_buf == (void *)UINT_MAX)
251 {
252 dprintf(CRITICAL, "ERROR: Invalid DTBO image buf addr\n");
253 ret = DTBO_NOT_SUPPORTED;
254 goto out;
255 }
256
Mayank Grover8f46a892018-09-10 13:24:59 +0530257 /* Add offset for salt buffer for verification */
258 dtbo_image_buf += SALT_BUFF_OFFSET;
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530259 /* Read dtbo partition with header */
260 if (mmc_read(ptn, (uint32_t *)(dtbo_image_buf), dtbo_partition_size))
261 {
262 dprintf(CRITICAL, "ERROR: dtbo partition mmc read failure \n");
263 ret = DTBO_ERROR;
264 goto out;
265 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530266 }
267
268 /* validate the dtbo image, before reading complete image */
269 dtbo_table_header = (struct dtbo_table_hdr *)dtbo_image_buf;
270
271 /*Check for dtbo magic*/
272 if (fdt32_to_cpu(dtbo_table_header->magic) != DTBO_TABLE_MAGIC)
273 {
274 dprintf(CRITICAL, "dtbo header magic mismatch %x, with %x\n",
275 fdt32_to_cpu(dtbo_table_header->magic), DTBO_TABLE_MAGIC);
276 ret = DTBO_ERROR;
277 goto out;
278 }
279
280 /*Check for dtbo image table size*/
281 if (fdt32_to_cpu(dtbo_table_header->hdr_size) != sizeof(struct dtbo_table_hdr))
282 {
283 dprintf(CRITICAL, "dtbo table header size got corrupted\n");
284 ret = DTBO_ERROR;
285 goto out;
286 }
287
288 /*Check for dt entry size of dtbo image*/
289 if (fdt32_to_cpu(dtbo_table_header->dt_entry_size) != sizeof(struct dtbo_table_entry))
290 {
291 dprintf(CRITICAL, "dtbo table dt entry size got corrupted\n");
292 ret = DTBO_ERROR;
293 goto out;
294 }
295
296 /*Total size of dtbo */
297 dtbo_total_size = fdt32_to_cpu(dtbo_table_header->total_size);
298 if (dtbo_total_size > dtbo_partition_size || dtbo_total_size == 0)
299 {
300 dprintf(CRITICAL, "dtbo table total size exceeded the dtbo buffer allocated\n");
301 ret = DTBO_ERROR;
302 goto out;
303 }
304
305 /* Total size of dtbo entries */
306 dtbo_total_size = fdt32_to_cpu(dtbo_table_header->dt_entry_count) *
307 fdt32_to_cpu(dtbo_table_header->dt_entry_size);
308 if (dtbo_total_size > dtbo_partition_size || dtbo_total_size == 0)
309 {
310 dprintf(CRITICAL, "dtbo table total size exceeded the dtbo buffer allocated\n");
311 ret = DTBO_ERROR;
312 goto out;
313 }
314
315 /* Offset should be less than image size */
316 if (fdt32_to_cpu(dtbo_table_header->dt_entry_offset) > dtbo_partition_size)
317 {
318 dprintf(CRITICAL, "dtbo offset exceeds the dtbo buffer allocated\n");
319 ret = DTBO_ERROR;
320 goto out;
321 }
322
323 /* Offset + total size is less than image size */
324 if (dtbo_total_size + fdt32_to_cpu(dtbo_table_header->dt_entry_offset) > dtbo_partition_size)
325 {
326 dprintf(CRITICAL, "dtbo size exceeded the dtbo buffer allocated\n");
327 ret = DTBO_ERROR;
328 }
329
330out:
Mayank Groverb61c0c22018-09-04 15:09:32 +0530331 if (ret == DTBO_SUCCESS)
332 {
333 *dtbo_buf = dtbo_image_buf;
334 *dtbo_image_sz = (uint32_t)ptn_size;
335 dtbo_loaded = true;
336 }
337 else
338 {
339 *dtbo_buf = NULL;
340 *dtbo_image_sz = 0;
341 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530342 return ret;
343}
344
345static bool check_all_bits_set(uint32_t matchdt_value)
346{
347 return (matchdt_value & ALL_BITS_SET) == (ALL_BITS_SET);
348}
349
350/* Dt selection table for quick reference
351 | SNO | Dt Property | CDT Property | Exact | Best | Default |
352 |-----+---------------+-----------------+-------+------+---------+
353 | | qcom, msm-id | | | | |
354 | | | PlatformId | Y | N | N |
355 | | | SocRev | N | Y | N |
356 | | | FoundryId | Y | N | 0 |
357 | | qcom,board-id | | | | |
358 | | | VariantId | Y | N | N |
359 | | | VariantMajor | N | Y | N |
360 | | | VariantMinor | N | Y | N |
361 | | | PlatformSubtype | Y | N | 0 |
362 | | qcom,pmic-id | | | | |
363 | | | PmicModelId | Y | N | 0 |
364 | | | PmicMetalRev | N | Y | N |
365 | | | PmicLayerRev | N | Y | N |
366 | | | PmicVariantRev | N | Y | N |
367*/
368
lijuang0cce8bf2018-08-23 10:56:42 +0800369static 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 +0530370{
371 int board_id_len;
372 int platform_id_len = 0;
373 int pmic_id_len;
374 int root_offset = 0;
375 void *dtb = current_dtb_info->dtb;
376 uint32_t idx;
377 const char *platform_prop = NULL;
378 const char *board_prop = NULL;
379 const char *pmic_prop = NULL;
lijuang0cce8bf2018-08-23 10:56:42 +0800380 boolean find_best_match = false;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530381
382 current_dtb_info->dt_match_val = 0;
383 root_offset = fdt_path_offset(dtb, "/");
384 if (root_offset < 0) {
385 dprintf(CRITICAL, "ERROR: Unable to locate root node\n");
lijuang0cce8bf2018-08-23 10:56:42 +0800386 return false;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530387 }
388
389 /* Get the msm-id prop from DTB and find best match */
390 platform_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,msm-id", &platform_id_len);
391 if (platform_prop && (platform_id_len > 0) && (!(platform_id_len % PLAT_ID_SIZE))) {
392 /*Compare msm-id of the dtb vs board*/
393 current_dtb_info->dt_platform_id = fdt32_to_cpu(((struct plat_id *)platform_prop)->platform_id);
394 dprintf(SPEW, "Board SOC ID = %x | DT SOC ID = %x\n", (board_platform_id() & SOC_MASK),
395 (current_dtb_info->dt_platform_id & SOC_MASK));
396 if ((board_platform_id() & SOC_MASK) == (current_dtb_info->dt_platform_id & SOC_MASK)) {
397 current_dtb_info->dt_match_val |= BIT(SOC_MATCH);
398 } else {
399 dprintf(SPEW, "qcom,msm-id does not match\n");
400 /* If soc doesn't match, don't select dtb */
401 current_dtb_info->dt_match_val = BIT(NONE_MATCH);
402 goto cleanup;
403 }
404 /*Compare soc rev of the dtb vs board*/
405 current_dtb_info->dt_soc_rev = fdt32_to_cpu(((struct plat_id *)platform_prop)->soc_rev);
406 dprintf(SPEW, "Board SOC Rev = %x | DT SOC Rev =%x\n", board_soc_version(),
407 current_dtb_info->dt_soc_rev);
408 if (current_dtb_info->dt_soc_rev == board_soc_version()) {
409 current_dtb_info->dt_match_val |= BIT(VERSION_EXACT_MATCH);
410 } else if (current_dtb_info->dt_soc_rev < board_soc_version()) {
411 current_dtb_info->dt_match_val |= BIT(VERSION_BEST_MATCH);
412 } else if (current_dtb_info->dt_soc_rev) {
413 dprintf(SPEW, "SOC version does not match\n");
414 }
415 /*Compare Foundry Id of the dtb vs Board*/
416 current_dtb_info->dt_foundry_id = fdt32_to_cpu(((struct plat_id *)platform_prop)->platform_id) & FOUNDRY_ID_MASK;
417 dprintf (SPEW, "Board Foundry id = %x | DT Foundry id = %x\n", (board_foundry_id() << PLATFORM_FOUNDRY_SHIFT), current_dtb_info->dt_foundry_id);
418 if (current_dtb_info->dt_foundry_id == (board_foundry_id() << PLATFORM_FOUNDRY_SHIFT)) {
419 current_dtb_info->dt_match_val |= BIT (FOUNDRYID_EXACT_MATCH);
420 } else if (current_dtb_info->dt_foundry_id == 0 ){
421 current_dtb_info->dt_match_val |= BIT (FOUNDRYID_DEFAULT_MATCH);
422 } else {
423 dprintf(SPEW, "soc foundry does not match\n");
424 /* If soc doesn't match, don't select dtb */
425 current_dtb_info->dt_match_val = BIT(NONE_MATCH);
426 goto cleanup;
427 }
428 } else {
429 dprintf(SPEW, "qcom,msm-id does not exist (or) is (%d) not a multiple of (%d)\n", platform_id_len, PLAT_ID_SIZE);
430 }
431
432 /* Get the properties like variant id, subtype from DTB and compare the DTB vs Board */
433 board_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,board-id", &board_id_len);
434 if (board_prop && (board_id_len > 0) && (!(board_id_len % BOARD_ID_SIZE))) {
435 current_dtb_info->dt_variant_id = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id);
436 current_dtb_info->dt_platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->platform_subtype);
437 if (current_dtb_info->dt_platform_subtype == 0)
438 current_dtb_info->dt_platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id) >> PLATFORM_SUBTYPE_SHIFT_ID;
439
440 dprintf(SPEW, "Board variant id = %x | DT variant id = %x\n",board_hardware_id(), current_dtb_info->dt_variant_id);
441
442 current_dtb_info->dt_variant_major = current_dtb_info->dt_variant_id & VARIANT_MAJOR_MASK;
443 current_dtb_info->dt_variant_minor = current_dtb_info->dt_variant_id & VARIANT_MINOR_MASK;
444 current_dtb_info->dt_variant_id = current_dtb_info->dt_variant_id & VARIANT_MASK;
445
446 if (current_dtb_info->dt_variant_id == board_hardware_id()) {
447 current_dtb_info->dt_match_val |= BIT(VARIANT_MATCH);
448 } else if (current_dtb_info->dt_variant_id) {
449 dprintf(SPEW, "qcom,board-id doesnot match\n");
450 /* If board variant doesn't match, don't select dtb */
451 current_dtb_info->dt_match_val = BIT(NONE_MATCH);
452 goto cleanup;
453 }
454
455 if (current_dtb_info->dt_variant_major == (board_target_id() & VARIANT_MAJOR_MASK)) {
456 current_dtb_info->dt_match_val |= BIT(VARIANT_MAJOR_EXACT_MATCH);
457 } else if (current_dtb_info->dt_variant_major < (board_target_id() & VARIANT_MAJOR_MASK)) {
458 current_dtb_info->dt_match_val |= BIT(VARIANT_MAJOR_BEST_MATCH);
459 } else if (current_dtb_info->dt_variant_major) {
460 dprintf(SPEW, "qcom,board-id major version doesnot match\n");
461 }
462
463 if (current_dtb_info->dt_variant_minor == (board_target_id() & VARIANT_MINOR_MASK)) {
464 current_dtb_info->dt_match_val |= BIT(VARIANT_MINOR_EXACT_MATCH);
465 } else if (current_dtb_info->dt_variant_minor < (board_target_id() & VARIANT_MINOR_MASK)) {
466 current_dtb_info->dt_match_val |= BIT(VARIANT_MINOR_BEST_MATCH);
467 } else if (current_dtb_info->dt_variant_minor) {
468 dprintf(SPEW, "qcom,board-id minor version doesnot match\n");
469 }
470
471 dprintf(SPEW, "Board platform subtype = %x | DT platform subtype = %x\n",
472 board_hardware_subtype(), current_dtb_info->dt_platform_subtype);
473 if (current_dtb_info->dt_platform_subtype == board_hardware_subtype()) {
474 current_dtb_info->dt_match_val |= BIT(SUBTYPE_EXACT_MATCH);
475 } else if (current_dtb_info->dt_platform_subtype == 0) {
476 current_dtb_info->dt_match_val |= BIT(SUBTYPE_DEFAULT_MATCH);
477 } else if (current_dtb_info->dt_platform_subtype) {
478 dprintf(SPEW, "subtype id doesnot match\n");
479 /* If board platform doesn't match, don't select dtb */
480 current_dtb_info->dt_match_val = BIT(NONE_MATCH);
481 goto cleanup;
482 }
483 } else {
484 dprintf(SPEW, "qcom,board-id does not exist (or)(%d) is not a multiple of (%d)\n",
485 board_id_len, BOARD_ID_SIZE);
486 }
487
488 /* Get the pmic property from DTB then compare the DTB vs Board */
489 pmic_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,pmic-id", &pmic_id_len);
490 if (pmic_prop && (pmic_id_len > 0) && (!(pmic_id_len % sizeof(struct pmic_id))))
491 {
492 pmic_info curr_pmic_info;
493 pmic_info best_pmic_info;
494 unsigned int pmic_entry_indx;
495 unsigned int pmic_entries_count;
496
497 /* Find all pmic entries count */
498 pmic_entries_count = pmic_id_len/sizeof(struct pmic_id);
499
500 memset(&best_pmic_info, 0, sizeof(pmic_info));
501 for (pmic_entry_indx = 0; pmic_entry_indx < pmic_entries_count; pmic_entry_indx++)
502 {
503 memset(&curr_pmic_info, 0, sizeof(pmic_info));
504
505 /* Read all pmic info */
506 /* Compare with board pmic */
507 for (idx = 0; idx < MAX_PMIC_IDX; idx++)
508 {
509 curr_pmic_info.dt_pmic_model[idx] =
510 fdt32_to_cpu (((struct pmic_id *)pmic_prop)->pmic_version[idx]);
511 dprintf(SPEW, "pmic_data[%u]:%x\n", idx, curr_pmic_info.dt_pmic_model[idx]);
512 curr_pmic_info.dt_pmic_rev[idx] =
513 curr_pmic_info.dt_pmic_model[idx] & PMIC_REV_MASK;
514 curr_pmic_info.dt_pmic_model[idx] =
515 curr_pmic_info.dt_pmic_model[idx] & PMIC_MODEL_MASK;
516
517 /* Compare with board pmic information & Update bit mask */
518 if (curr_pmic_info.dt_pmic_model[idx] == (board_pmic_target(idx) & PMIC_MODEL_MASK))
519 curr_pmic_info.dt_match_val |= BIT (PMIC_MATCH_EXACT_MODEL_IDX0 + idx * PMIC_SHIFT_IDX);
520 else if (curr_pmic_info.dt_pmic_model[idx] == 0)
521 curr_pmic_info.dt_match_val |= BIT (PMIC_MATCH_DEFAULT_MODEL_IDX0 + idx * PMIC_SHIFT_IDX);
522 else
523 {
524 curr_pmic_info.dt_match_val |= BIT (NONE_MATCH);
525 dprintf(SPEW, "PMIC Model doesn't match\n");
526 break; /* go to next pmic entry */
527 }
528
529 if (curr_pmic_info.dt_pmic_rev[idx] == (board_pmic_target(idx) & PMIC_REV_MASK))
530 curr_pmic_info.dt_match_val |= BIT(PMIC_MATCH_EXACT_REV_IDX0 + idx * PMIC_SHIFT_IDX);
531 else if (curr_pmic_info.dt_pmic_rev[idx] < (board_pmic_target(idx) & PMIC_REV_MASK))
532 curr_pmic_info.dt_match_val |= BIT(PMIC_MATCH_BEST_REV_IDX0 + idx * PMIC_SHIFT_IDX);
lijuangf1b8e1d2018-03-01 14:40:37 +0800533 else {
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530534 dprintf(SPEW, "PMIC revision doesn't match\n");
535 break; /* go to next pmic entry */
lijuangf1b8e1d2018-03-01 14:40:37 +0800536 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530537 }
538
539 dprintf(SPEW, "Bestpmicinfo.dtmatchval : %x | cur_pmic_info.dtmatchval: %x\n",
540 best_pmic_info.dt_match_val, curr_pmic_info.dt_match_val);
541
542 /* Update best pmic info, if required */
543 if(best_pmic_info.dt_match_val < curr_pmic_info.dt_match_val)
544 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
545 else if (best_pmic_info.dt_match_val == curr_pmic_info.dt_match_val)
546 {
547 if (best_pmic_info.dt_pmic_rev[PMIC_IDX0] < curr_pmic_info.dt_pmic_rev[PMIC_IDX0])
548 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
549 else if (best_pmic_info.dt_pmic_rev[PMIC_IDX1] < curr_pmic_info.dt_pmic_rev[PMIC_IDX1])
550 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
551 else if (best_pmic_info.dt_pmic_rev[PMIC_IDX2] < curr_pmic_info.dt_pmic_rev[PMIC_IDX2])
552 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
553 else if (best_pmic_info.dt_pmic_rev[PMIC_IDX3] < curr_pmic_info.dt_pmic_rev[PMIC_IDX3])
554 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
555 }
556
557 /* Increment to next pmic entry */
558 pmic_prop += sizeof (struct pmic_id);
559 }
560
561 dprintf(SPEW, "Best pmic info 0x%0x/0x%x/0x%x/0x%0x for current dt\n",
562 best_pmic_info.dt_pmic_model[PMIC_IDX0],
563 best_pmic_info.dt_pmic_model[PMIC_IDX1],
564 best_pmic_info.dt_pmic_model[PMIC_IDX2],
565 best_pmic_info.dt_pmic_model[PMIC_IDX3]);
566
567 current_dtb_info->dt_match_val |= best_pmic_info.dt_match_val;
568 current_dtb_info->dt_pmic_rev[PMIC_IDX0] = best_pmic_info.dt_pmic_rev[PMIC_IDX0];
569 current_dtb_info->dt_pmic_model[PMIC_IDX0] = best_pmic_info.dt_pmic_model[PMIC_IDX0];
570 current_dtb_info->dt_pmic_rev[PMIC_IDX1] = best_pmic_info.dt_pmic_rev[PMIC_IDX1];
571 current_dtb_info->dt_pmic_model[PMIC_IDX1] = best_pmic_info.dt_pmic_model[PMIC_IDX1];
572 current_dtb_info->dt_pmic_rev[PMIC_IDX2] = best_pmic_info.dt_pmic_rev[PMIC_IDX2];
573 current_dtb_info->dt_pmic_model[PMIC_IDX2] = best_pmic_info.dt_pmic_model[PMIC_IDX2];
574 current_dtb_info->dt_pmic_rev[PMIC_IDX3] = best_pmic_info.dt_pmic_rev[PMIC_IDX3];
575 current_dtb_info->dt_pmic_model[PMIC_IDX3] = best_pmic_info.dt_pmic_model[PMIC_IDX3];
576 }
577 else
578 {
579 dprintf(SPEW, "qcom,pmic-id does not exit (or) is (%d) not a multiple of (%d)\n",
580 pmic_id_len, PMIC_ID_SIZE);
581 }
582
583cleanup:
584 if (current_dtb_info->dt_match_val & BIT(exact_match)) {
lijuang0cce8bf2018-08-23 10:56:42 +0800585 if (best_dtb_info->dt_match_val < current_dtb_info->dt_match_val) {
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530586 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
lijuang0cce8bf2018-08-23 10:56:42 +0800587 find_best_match = true;
588 } else if (best_dtb_info->dt_match_val == current_dtb_info->dt_match_val) {
589 find_best_match = true;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530590 if (best_dtb_info->dt_soc_rev < current_dtb_info->dt_soc_rev)
591 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
592 else if (best_dtb_info->dt_variant_major < current_dtb_info->dt_variant_major)
593 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
594 else if (best_dtb_info->dt_variant_minor < current_dtb_info->dt_variant_minor)
595 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
596 else if (best_dtb_info->dt_pmic_rev[0] < current_dtb_info->dt_pmic_rev[0])
597 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
598 else if (best_dtb_info->dt_pmic_rev[1] < current_dtb_info->dt_pmic_rev[1])
599 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
600 else if (best_dtb_info->dt_pmic_rev[2] < current_dtb_info->dt_pmic_rev[2])
601 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
602 else if (best_dtb_info->dt_pmic_rev[3] < current_dtb_info->dt_pmic_rev[3])
603 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
lijuang0cce8bf2018-08-23 10:56:42 +0800604 else
605 find_best_match = false;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530606 }
607 }
lijuang0cce8bf2018-08-23 10:56:42 +0800608
609 return find_best_match;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530610}
611
612void *get_soc_dtb(void *kernel, uint32_t kernel_size, uint32_t dtb_offset)
613{
614 uintptr_t kernel_end_offset = (uintptr_t)kernel + kernel_size;
615 void *dtb = NULL;
616 struct fdt_header dtb_header;
617 uint32_t dtb_size = 0;
618 dt_info cur_dtb_info = {0};
619 dt_info best_dtb_info = {0};
620
621 if (!dtb_offset){
622 dprintf(CRITICAL, "DTB offset is NULL\n");
623 return NULL;
624 }
625 if (((uintptr_t)kernel + (uintptr_t)dtb_offset) < (uintptr_t)kernel) {
626 return NULL;
627 }
628 dtb = kernel + dtb_offset;
629 while (((uintptr_t)dtb + sizeof(struct fdt_header)) < (uintptr_t)kernel_end_offset) {
630 /* the DTB could be unaligned, so extract the header,
631 * and operate on it separately */
632 memscpy(&dtb_header, sizeof(struct fdt_header), dtb, sizeof(struct fdt_header));
633 dtb_size = fdt_totalsize((const void *)&dtb_header);
634 if (fdt_check_header((const void *)&dtb_header) != 0 ||
635 fdt_check_header_ext((void *)&dtb_header) != 0 ||
636 ((uintptr_t)dtb + dtb_size < (uintptr_t)dtb) ||
637 ((uintptr_t)dtb + dtb_size > (uintptr_t)kernel_end_offset))
638 break;
639
640 cur_dtb_info.dtb = dtb;
641 dtb_read_find_match(&cur_dtb_info, &best_dtb_info, SOC_MATCH);
642 if (cur_dtb_info.dt_match_val) {
643 if (cur_dtb_info.dt_match_val & BIT(SOC_MATCH)) {
644 if (check_all_bits_set(cur_dtb_info.dt_match_val)) {
645 dprintf(CRITICAL, "Exact DTB match found. dtbo search is not required\n");
646 dtbo_needed = false;
647 }
648 }
649 }
650 dprintf(SPEW, "Best Match DTB VAL = %x\n", best_dtb_info.dt_match_val);
651 dtb += dtb_size;
652 }
653 if (!best_dtb_info.dtb) {
654 dprintf(CRITICAL, "No match found for soc dtb type\n");
655 return NULL;
656 }
657 return best_dtb_info.dtb;
658}
659
660void *get_board_dtb(void *dtbo_image_buf)
661{
662 struct dtbo_table_hdr *dtbo_table_header = dtbo_image_buf;
663 struct dtbo_table_entry *dtb_table_entry = NULL;
664 uint32_t dtbo_count = 0;
665 void *board_dtb = NULL;
666 uint32_t dtbo_table_entries_count = 0;
667 uint32_t first_dtbo_table_entry_offset = 0;
668 struct fdt_header dtb_header;
669 uint32_t dtb_size = 0;
670 dt_info cur_dtb_info = {0};
671 dt_info best_dtb_info = {0};
lijuang0cce8bf2018-08-23 10:56:42 +0800672 boolean find_best_dtb = false;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530673
674 if (!dtbo_image_buf) {
675 dprintf(CRITICAL, "dtbo image buffer is NULL\n");
676 return NULL;
677 }
678
679 first_dtbo_table_entry_offset = fdt32_to_cpu(dtbo_table_header->dt_entry_offset);
680 if ((uintptr_t)dtbo_image_buf > ((uintptr_t)dtbo_image_buf + (uintptr_t)first_dtbo_table_entry_offset))
681 {
682 dprintf(CRITICAL, "dtbo table entry offset is invalid\n");
683 return NULL;
684 }
685 dtb_table_entry = (struct dtbo_table_entry *)(dtbo_image_buf + first_dtbo_table_entry_offset);
686 dtbo_table_entries_count = fdt32_to_cpu(dtbo_table_header->dt_entry_count);
687 for (dtbo_count = 0; dtbo_count < dtbo_table_entries_count; dtbo_count++) {
688 board_dtb = dtbo_image_buf + fdt32_to_cpu(dtb_table_entry->dt_offset);
689 /* The DTB could be unaligned, so extract the header,
690 * and operate on it separately */
691 memscpy(&dtb_header, sizeof(struct fdt_header), board_dtb, sizeof(struct fdt_header));
692 dtb_size = fdt_totalsize((const void *)&dtb_header);
693 if (fdt_check_header((const void *)&dtb_header) != 0 ||
694 fdt_check_header_ext((void *)&dtb_header) != 0 ||
695 ((uintptr_t)board_dtb + dtb_size < (uintptr_t)board_dtb)) {
696 dprintf(CRITICAL, "No valid board dtb found\n");
697 break;
698 }
699 dprintf(SPEW, "Valid board dtb is found\n");
700 cur_dtb_info.dtb = board_dtb;
lijuang0cce8bf2018-08-23 10:56:42 +0800701 find_best_dtb = dtb_read_find_match(&cur_dtb_info, &best_dtb_info, VARIANT_MATCH);
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530702 dprintf(SPEW, "dtbo count = %u local_board_dt_match =%x\n",dtbo_count, cur_dtb_info.dt_match_val);
703 dtb_table_entry++;
lijuang0cce8bf2018-08-23 10:56:42 +0800704
705 if (find_best_dtb) {
706 dtbo_idx = dtbo_count;
707 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530708 }
709 if (!best_dtb_info.dtb) {
710 dprintf(CRITICAL, "Unable to find the board dtb\n");
711 return NULL;
712 }
713 return best_dtb_info.dtb;
714}
715
Lijuan Gao9f152862014-08-18 13:45:24 +0800716static void insert_dt_entry_in_queue(struct dt_entry_node *dt_list, struct dt_entry_node *dt_node_member)
717{
718 list_add_tail(&dt_list->node, &dt_node_member->node);
719}
720
721static void dt_entry_list_delete(struct dt_entry_node *dt_node_member)
722{
723 if (list_in_list(&dt_node_member->node)) {
724 list_delete(&dt_node_member->node);
725 free(dt_node_member->dt_entry_m);
726 free(dt_node_member);
727 }
728}
729
730static int dev_tree_compatible(void *dtb, uint32_t dtb_size, struct dt_entry_node *dtb_list)
Dima Zavinc46f8382013-05-03 12:23:06 -0700731{
732 int root_offset;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700733 const void *prop = NULL;
734 const char *plat_prop = NULL;
735 const char *board_prop = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800736 const char *pmic_prop = NULL;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700737 char *model = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800738 struct dt_entry *cur_dt_entry;
739 struct dt_entry *dt_entry_array = NULL;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700740 struct board_id *board_data = NULL;
741 struct plat_id *platform_data = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800742 struct pmic_id *pmic_data = NULL;
Dima Zavinc46f8382013-05-03 12:23:06 -0700743 int len;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700744 int len_board_id;
745 int len_plat_id;
746 int min_plat_id_len = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800747 int len_pmic_id;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700748 uint32_t dtb_ver;
749 uint32_t num_entries = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800750 uint32_t i, j, k, n;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700751 uint32_t msm_data_count;
752 uint32_t board_data_count;
Lijuan Gao9f152862014-08-18 13:45:24 +0800753 uint32_t pmic_data_count;
Dima Zavinc46f8382013-05-03 12:23:06 -0700754
755 root_offset = fdt_path_offset(dtb, "/");
756 if (root_offset < 0)
757 return false;
758
759 prop = fdt_getprop(dtb, root_offset, "model", &len);
760 if (prop && len > 0) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700761 model = (char *) malloc(sizeof(char) * len);
762 ASSERT(model);
763 strlcpy(model, prop, len);
Dima Zavinc46f8382013-05-03 12:23:06 -0700764 } else {
vijay kumar89d36d82014-06-30 19:32:18 +0530765 dprintf(INFO, "model does not exist in device tree\n");
Dima Zavinc46f8382013-05-03 12:23:06 -0700766 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800767 /* Find the pmic-id prop from DTB , if pmic-id is present then
768 * the DTB is version 3, otherwise find the board-id prop from DTB ,
769 * if board-id is present then the DTB is version 2 */
770 pmic_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,pmic-id", &len_pmic_id);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700771 board_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,board-id", &len_board_id);
Lijuan Gao9f152862014-08-18 13:45:24 +0800772 if (pmic_prop && (len_pmic_id > 0) && board_prop && (len_board_id > 0)) {
773 if ((len_pmic_id % PMIC_ID_SIZE) || (len_board_id % BOARD_ID_SIZE))
774 {
775 dprintf(CRITICAL, "qcom,pmic-id(%d) or qcom,board-id(%d) in device tree is not a multiple of (%d %d)\n",
776 len_pmic_id, len_board_id, PMIC_ID_SIZE, BOARD_ID_SIZE);
777 return false;
778 }
779 dtb_ver = DEV_TREE_VERSION_V3;
780 min_plat_id_len = PLAT_ID_SIZE;
781 } else if (board_prop && len_board_id > 0) {
vijay kumar89d36d82014-06-30 19:32:18 +0530782 if (len_board_id % BOARD_ID_SIZE)
783 {
784 dprintf(CRITICAL, "qcom,board-id in device tree is (%d) not a multiple of (%d)\n",
785 len_board_id, BOARD_ID_SIZE);
786 return false;
787 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700788 dtb_ver = DEV_TREE_VERSION_V2;
789 min_plat_id_len = PLAT_ID_SIZE;
Lijuan Gao9f152862014-08-18 13:45:24 +0800790 } else {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700791 dtb_ver = DEV_TREE_VERSION_V1;
792 min_plat_id_len = DT_ENTRY_V1_SIZE;
793 }
794
795 /* Get the msm-id prop from DTB */
796 plat_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,msm-id", &len_plat_id);
797 if (!plat_prop || len_plat_id <= 0) {
Dima Zavinc46f8382013-05-03 12:23:06 -0700798 dprintf(INFO, "qcom,msm-id entry not found\n");
799 return false;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700800 } else if (len_plat_id % min_plat_id_len) {
801 dprintf(INFO, "qcom,msm-id in device tree is (%d) not a multiple of (%d)\n",
802 len_plat_id, min_plat_id_len);
Dima Zavinc46f8382013-05-03 12:23:06 -0700803 return false;
804 }
Dima Zavinc46f8382013-05-03 12:23:06 -0700805
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700806 /*
807 * If DTB version is '1' look for <x y z> pair in the DTB
808 * x: platform_id
809 * y: variant_id
810 * z: SOC rev
811 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800812 if (dtb_ver == DEV_TREE_VERSION_V1) {
813 cur_dt_entry = (struct dt_entry *)
814 malloc(sizeof(struct dt_entry));
Dima Zavinc46f8382013-05-03 12:23:06 -0700815
Lijuan Gao9f152862014-08-18 13:45:24 +0800816 if (!cur_dt_entry) {
817 dprintf(CRITICAL, "Out of memory\n");
818 return false;
819 }
820 memset(cur_dt_entry, 0, sizeof(struct dt_entry));
821
822 while (len_plat_id) {
823 cur_dt_entry->platform_id = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->platform_id);
824 cur_dt_entry->variant_id = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->variant_id);
825 cur_dt_entry->soc_rev = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->soc_rev);
826 cur_dt_entry->board_hw_subtype =
827 fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->variant_id) >> 0x18;
828 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
829 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
830 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
831 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
832 cur_dt_entry->offset = (uint32_t)dtb;
833 cur_dt_entry->size = dtb_size;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700834
835 dprintf(SPEW, "Found an appended flattened device tree (%s - %u %u 0x%x)\n",
Lijuan Gao9f152862014-08-18 13:45:24 +0800836 *model ? model : "unknown",
837 cur_dt_entry->platform_id, cur_dt_entry->variant_id, cur_dt_entry->soc_rev);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700838
Lijuan Gao9f152862014-08-18 13:45:24 +0800839 if (platform_dt_absolute_match(cur_dt_entry, dtb_list)) {
840 dprintf(SPEW, "Device tree exact match the board: <%u %u 0x%x> != <%u %u 0x%x>\n",
841 cur_dt_entry->platform_id,
842 cur_dt_entry->variant_id,
843 cur_dt_entry->soc_rev,
844 board_platform_id(),
845 board_hardware_id(),
846 board_soc_version());
847
848 } else {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700849 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 +0800850 cur_dt_entry->platform_id,
851 cur_dt_entry->variant_id,
852 cur_dt_entry->soc_rev,
853 board_platform_id(),
854 board_hardware_id(),
855 board_soc_version());
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700856 plat_prop += DT_ENTRY_V1_SIZE;
857 len_plat_id -= DT_ENTRY_V1_SIZE;
858 continue;
859 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700860 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800861 free(cur_dt_entry);
862
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700863 }
864 /*
Lijuan Gao9f152862014-08-18 13:45:24 +0800865 * If DTB Version is '3' then we have split DTB with board & msm data & pmic
866 * populated saperately in board-id & msm-id & pmic-id prop respectively.
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700867 * Extract the data & prepare a look up table
868 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800869 else if (dtb_ver == DEV_TREE_VERSION_V2 || dtb_ver == DEV_TREE_VERSION_V3) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700870 board_data_count = (len_board_id / BOARD_ID_SIZE);
871 msm_data_count = (len_plat_id / PLAT_ID_SIZE);
Lijuan Gao9f152862014-08-18 13:45:24 +0800872 /* If dtb version is v2.0, the pmic_data_count will be <= 0 */
873 pmic_data_count = (len_pmic_id / PMIC_ID_SIZE);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700874
Lijuan Gao9f152862014-08-18 13:45:24 +0800875 /* If we are using dtb v3.0, then we have split board, msm & pmic data in the DTB
876 * If we are using dtb v2.0, then we have split board & msmdata in the DTB
877 */
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700878 board_data = (struct board_id *) malloc(sizeof(struct board_id) * (len_board_id / BOARD_ID_SIZE));
879 ASSERT(board_data);
880 platform_data = (struct plat_id *) malloc(sizeof(struct plat_id) * (len_plat_id / PLAT_ID_SIZE));
881 ASSERT(platform_data);
Lijuan Gao9f152862014-08-18 13:45:24 +0800882 if (dtb_ver == DEV_TREE_VERSION_V3) {
883 pmic_data = (struct pmic_id *) malloc(sizeof(struct pmic_id) * (len_pmic_id / PMIC_ID_SIZE));
884 ASSERT(pmic_data);
885 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700886 i = 0;
887
888 /* Extract board data from DTB */
Lijuan Gao9f152862014-08-18 13:45:24 +0800889 for(i = 0 ; i < board_data_count; i++) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700890 board_data[i].variant_id = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id);
891 board_data[i].platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->platform_subtype);
Lijuan Gao9f152862014-08-18 13:45:24 +0800892 /* For V2/V3 version of DTBs we have platform version field as part
893 * of variant ID, in such case the subtype will be mentioned as 0x0
894 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
895 * SS -- Subtype
896 * PM -- Platform major version
897 * Pm -- Platform minor version
898 * PH -- Platform hardware CDP/MTP
899 * In such case to make it compatible with LK algorithm move the subtype
900 * from variant_id to subtype field
901 */
902 if (board_data[i].platform_subtype == 0)
903 board_data[i].platform_subtype =
904 fdt32_to_cpu(((struct board_id *)board_prop)->variant_id) >> 0x18;
905
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700906 len_board_id -= sizeof(struct board_id);
907 board_prop += sizeof(struct board_id);
908 }
909
910 /* Extract platform data from DTB */
Lijuan Gao9f152862014-08-18 13:45:24 +0800911 for(i = 0 ; i < msm_data_count; i++) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700912 platform_data[i].platform_id = fdt32_to_cpu(((struct plat_id *)plat_prop)->platform_id);
913 platform_data[i].soc_rev = fdt32_to_cpu(((struct plat_id *)plat_prop)->soc_rev);
914 len_plat_id -= sizeof(struct plat_id);
915 plat_prop += sizeof(struct plat_id);
916 }
917
Lijuan Gao9f152862014-08-18 13:45:24 +0800918 if (dtb_ver == DEV_TREE_VERSION_V3 && pmic_prop) {
919 /* Extract pmic data from DTB */
920 for(i = 0 ; i < pmic_data_count; i++) {
921 pmic_data[i].pmic_version[0]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[0]);
922 pmic_data[i].pmic_version[1]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[1]);
923 pmic_data[i].pmic_version[2]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[2]);
924 pmic_data[i].pmic_version[3]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[3]);
925 len_pmic_id -= sizeof(struct pmic_id);
926 pmic_prop += sizeof(struct pmic_id);
927 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700928
Lijuan Gao9f152862014-08-18 13:45:24 +0800929 /* We need to merge board & platform data into dt entry structure */
930 num_entries = msm_data_count * board_data_count * pmic_data_count;
931 } else {
932 /* We need to merge board & platform data into dt entry structure */
933 num_entries = msm_data_count * board_data_count;
934 }
vijay kumar89d36d82014-06-30 19:32:18 +0530935
Lijuan Gao9f152862014-08-18 13:45:24 +0800936 if ((((uint64_t)msm_data_count * (uint64_t)board_data_count * (uint64_t)pmic_data_count) !=
937 msm_data_count * board_data_count * pmic_data_count) ||
938 (((uint64_t)msm_data_count * (uint64_t)board_data_count) != msm_data_count * board_data_count)) {
939
940 free(board_data);
941 free(platform_data);
942 if (pmic_data)
943 free(pmic_data);
944 if (model)
945 free(model);
946 return false;
947 }
948
949 dt_entry_array = (struct dt_entry*) malloc(sizeof(struct dt_entry) * num_entries);
950 ASSERT(dt_entry_array);
951
952 /* If we have '<X>; <Y>; <Z>' as platform data & '<A>; <B>; <C>' as board data.
953 * Then dt entry should look like
954 * <X ,A >;<X, B>;<X, C>;
955 * <Y ,A >;<Y, B>;<Y, C>;
956 * <Z ,A >;<Z, B>;<Z, C>;
957 */
958 i = 0;
959 k = 0;
960 n = 0;
961 for (i = 0; i < msm_data_count; i++) {
962 for (j = 0; j < board_data_count; j++) {
963 if (dtb_ver == DEV_TREE_VERSION_V3 && pmic_prop) {
964 for (n = 0; n < pmic_data_count; n++) {
965 dt_entry_array[k].platform_id = platform_data[i].platform_id;
966 dt_entry_array[k].soc_rev = platform_data[i].soc_rev;
967 dt_entry_array[k].variant_id = board_data[j].variant_id;
968 dt_entry_array[k].board_hw_subtype = board_data[j].platform_subtype;
969 dt_entry_array[k].pmic_rev[0]= pmic_data[n].pmic_version[0];
970 dt_entry_array[k].pmic_rev[1]= pmic_data[n].pmic_version[1];
971 dt_entry_array[k].pmic_rev[2]= pmic_data[n].pmic_version[2];
972 dt_entry_array[k].pmic_rev[3]= pmic_data[n].pmic_version[3];
973 dt_entry_array[k].offset = (uint32_t)dtb;
974 dt_entry_array[k].size = dtb_size;
975 k++;
976 }
977
978 } else {
979 dt_entry_array[k].platform_id = platform_data[i].platform_id;
980 dt_entry_array[k].soc_rev = platform_data[i].soc_rev;
981 dt_entry_array[k].variant_id = board_data[j].variant_id;
982 dt_entry_array[k].board_hw_subtype = board_data[j].platform_subtype;
983 dt_entry_array[k].pmic_rev[0]= board_pmic_target(0);
984 dt_entry_array[k].pmic_rev[1]= board_pmic_target(1);
985 dt_entry_array[k].pmic_rev[2]= board_pmic_target(2);
986 dt_entry_array[k].pmic_rev[3]= board_pmic_target(3);
987 dt_entry_array[k].offset = (uint32_t)dtb;
988 dt_entry_array[k].size = dtb_size;
vijay kumar89d36d82014-06-30 19:32:18 +0530989 k++;
990 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700991 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800992 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700993
Lijuan Gao9f152862014-08-18 13:45:24 +0800994 for (i=0 ;i < num_entries; i++) {
995 dprintf(SPEW, "Found an appended flattened device tree (%s - %u %u %u 0x%x)\n",
996 *model ? model : "unknown",
997 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 +0530998
Lijuan Gao9f152862014-08-18 13:45:24 +0800999 if (platform_dt_absolute_match(&(dt_entry_array[i]), dtb_list)) {
1000 dprintf(SPEW, "Device tree exact match the board: <%u %u %u 0x%x> == <%u %u %u 0x%x>\n",
1001 dt_entry_array[i].platform_id,
1002 dt_entry_array[i].variant_id,
1003 dt_entry_array[i].soc_rev,
1004 dt_entry_array[i].board_hw_subtype,
1005 board_platform_id(),
1006 board_hardware_id(),
1007 board_hardware_subtype(),
1008 board_soc_version());
vijay kumar89d36d82014-06-30 19:32:18 +05301009
Lijuan Gao9f152862014-08-18 13:45:24 +08001010 } else {
1011 dprintf(SPEW, "Device tree's msm_id doesn't match the board: <%u %u %u 0x%x> != <%u %u %u 0x%x>\n",
1012 dt_entry_array[i].platform_id,
1013 dt_entry_array[i].variant_id,
1014 dt_entry_array[i].soc_rev,
1015 dt_entry_array[i].board_hw_subtype,
1016 board_platform_id(),
1017 board_hardware_id(),
1018 board_hardware_subtype(),
1019 board_soc_version());
Channagoud Kadabia4dbe332013-09-05 17:44:11 -07001020 }
1021 }
Lijuan Gao9f152862014-08-18 13:45:24 +08001022
1023 free(board_data);
1024 free(platform_data);
1025 if (pmic_data)
1026 free(pmic_data);
1027 free(dt_entry_array);
Dima Zavinc46f8382013-05-03 12:23:06 -07001028 }
Lijuan Gao9f152862014-08-18 13:45:24 +08001029 if (model)
vijay kumar89d36d82014-06-30 19:32:18 +05301030 free(model);
Lijuan Gao9f152862014-08-18 13:45:24 +08001031 return true;
Dima Zavinc46f8382013-05-03 12:23:06 -07001032}
1033
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301034/* function to handle the overlay in independent thread */
1035static int dtb_overlay_handler(void *args)
1036{
1037 dprintf(SPEW, "thread %s() started\n", __func__);
1038
1039 soc_dtb_hdr = ufdt_install_blob(soc_dtb, fdt_totalsize(soc_dtb));
1040 if(!soc_dtb_hdr)
1041 {
1042 dprintf(CRITICAL, "ERROR: Install Blob failed\n");
1043 ret = DTBO_ERROR;
1044 goto out;
1045 }
1046 final_dtb_hdr = ufdt_apply_overlay(soc_dtb_hdr, fdt_totalsize(soc_dtb_hdr),board_dtb,
1047 fdt_totalsize(board_dtb));
1048 if (!final_dtb_hdr)
1049 {
1050 dprintf(CRITICAL, "ERROR: UFDT apply overlay failed\n");
1051 ret = DTBO_ERROR;
1052 goto out;
1053 }
1054out:
1055 /* This flag can only be updated here, hence it is not protected */
1056 event_signal(&dtbo_event, true);
1057 thread_exit(0);
1058 return 0;
1059}
1060
1061/*
1062 * Function to check and form new dtb with Overlay support.
1063*/
1064dtbo_error dev_tree_appended_with_dtbo(void *kernel, uint32_t kernel_size,
1065 uint32_t dtb_offset, void *tags)
1066{
1067 void *dtbo_image_buf = NULL;
Mayank Groverb61c0c22018-09-04 15:09:32 +05301068 uint32_t dtbo_image_sz = 0;
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301069
Mayank Grover302432a2017-12-08 17:18:58 +05301070 bs_set_timestamp(BS_DTB_OVERLAY_START);
Mayank Groverb61c0c22018-09-04 15:09:32 +05301071 ret = load_validate_dtbo_image(&dtbo_image_buf, &dtbo_image_sz);
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301072 if (ret == DTBO_SUCCESS)
1073 {
1074 final_dtb_hdr = soc_dtb = get_soc_dtb(kernel,
1075 kernel_size, dtb_offset);
1076 if(!soc_dtb)
1077 {
1078 ret = DTBO_ERROR;
1079 goto out;
1080 }
1081
1082 if (dtbo_needed)
1083 {
1084 board_dtb = get_board_dtb(dtbo_image_buf);
1085 if(!board_dtb)
1086 {
1087 ret = DTBO_ERROR;
1088 goto out;
1089 }
1090
1091 if((ADD_OF((fdt_totalsize(soc_dtb)), (fdt_totalsize(board_dtb)))) > MAX_DTBO_SZ)
1092 {
1093 dprintf(CRITICAL, "ERROR: dtb greater than max supported.\n");
1094 ret = DTBO_ERROR;
1095 goto out;
1096 }
1097
1098 /*
1099 spawn a seperate thread for dtbo overlay with indpendent,
1100 stack to avoid issues with stack corruption seen during flattening,
1101 of dtb in overlay functionality
1102 */
1103 {
1104 thread_t *thr = NULL;
1105 event_init(&dtbo_event, 0, EVENT_FLAG_AUTOUNSIGNAL);
1106 thr = thread_create("dtb_overlay", dtb_overlay_handler, 0,
1107 DEFAULT_PRIORITY, DTBO_STACK_SIZE);
1108 if (!thr)
1109 {
1110 dprintf(CRITICAL, "ERROR: Failed to create DTBO thread.\n");
1111 ret = DTBO_ERROR;
1112 goto out;
1113 }
1114 thread_resume(thr);
1115
1116 /* block current thread, untill woken up by dtb_overlay_handler. */
1117 event_wait(&dtbo_event);
1118
1119 /* ret is updated by dtb overlay thread, in case of error */
1120 if(ret == DTBO_ERROR)
1121 {
1122 goto out;
1123 }
1124 } /* dtbo_overlay_handler exited */
1125
1126 }
1127 memscpy(tags, fdt_totalsize(final_dtb_hdr), final_dtb_hdr,
1128 fdt_totalsize(final_dtb_hdr));
Mayank Grover71f63862018-05-03 17:06:41 +05301129 dprintf(INFO, "DTB overlay is successful\n");
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301130 }
1131 else
1132 {
Mayank Grover71f63862018-05-03 17:06:41 +05301133 dprintf(INFO, "ERROR: DTBO read is not valid\n DTB Overlay failed.\n");
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301134 ret = DTBO_NOT_SUPPORTED;
1135 }
1136out:
Mayank Grover302432a2017-12-08 17:18:58 +05301137 bs_set_timestamp(BS_DTB_OVERLAY_END);
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301138 return ret;
1139}
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001140/*
Dima Zavin77e41f32013-03-06 16:10:43 -08001141 * Will relocate the DTB to the tags addr if the device tree is found and return
1142 * its address
1143 *
1144 * Arguments: kernel - Start address of the kernel loaded in RAM
1145 * tags - Start address of the tags loaded in RAM
Channagoud Kadabi704cd562013-04-25 15:19:59 -07001146 * kernel_size - Size of the kernel in bytes
1147 *
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001148 * Return Value: DTB address : If appended device tree is found
Dima Zavin77e41f32013-03-06 16:10:43 -08001149 * 'NULL' : Otherwise
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001150 */
Matthew Qinbb7923d2015-02-09 10:56:09 +08001151void *dev_tree_appended(void *kernel, uint32_t kernel_size, uint32_t dtb_offset, void *tags)
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001152{
Parth Dixit97e47bb2016-03-07 17:20:44 +05301153 uintptr_t kernel_end = (uintptr_t)kernel + kernel_size;
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001154 uint32_t app_dtb_offset = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +08001155 void *dtb = NULL;
Shashank Mittalc0f10282013-07-15 14:53:31 -07001156 void *bestmatch_tag = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +08001157 struct dt_entry *best_match_dt_entry = NULL;
Shashank Mittalc0f10282013-07-15 14:53:31 -07001158 uint32_t bestmatch_tag_size;
Lijuan Gao9f152862014-08-18 13:45:24 +08001159 struct dt_entry_node *dt_entry_queue = NULL;
1160 struct dt_entry_node *dt_node_tmp1 = NULL;
1161 struct dt_entry_node *dt_node_tmp2 = NULL;
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301162 dtbo_error ret = DTBO_NOT_SUPPORTED;
1163
lijuangdc1b5422018-05-07 17:12:59 +08001164 if (dtb_offset)
1165 app_dtb_offset = dtb_offset;
1166 else
1167 memcpy((void*) &app_dtb_offset, (void*) (kernel + DTB_OFFSET), sizeof(uint32_t));
1168
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301169 /* Check for dtbo support */
lijuangdc1b5422018-05-07 17:12:59 +08001170 ret = dev_tree_appended_with_dtbo(kernel, kernel_size, app_dtb_offset, tags);
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301171 if (ret == DTBO_SUCCESS)
1172 return tags;
1173 else if (ret == DTBO_ERROR)
1174 return NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +08001175
Lijuan Gao9f152862014-08-18 13:45:24 +08001176 /* Initialize the dtb entry node*/
1177 dt_entry_queue = (struct dt_entry_node *)
1178 malloc(sizeof(struct dt_entry_node));
1179
1180 if (!dt_entry_queue) {
1181 dprintf(CRITICAL, "Out of memory\n");
1182 return NULL;
1183 }
1184 list_initialize(&dt_entry_queue->node);
1185
vijay kumare2a5ea82014-06-25 12:24:14 +05301186 if (((uintptr_t)kernel + (uintptr_t)app_dtb_offset) < (uintptr_t)kernel) {
1187 return NULL;
1188 }
Parth Dixit97e47bb2016-03-07 17:20:44 +05301189 dtb = (void *)((uintptr_t)kernel + app_dtb_offset);
1190
vijay kumare2a5ea82014-06-25 12:24:14 +05301191 while (((uintptr_t)dtb + sizeof(struct fdt_header)) < (uintptr_t)kernel_end) {
Dima Zavinc46f8382013-05-03 12:23:06 -07001192 struct fdt_header dtb_hdr;
1193 uint32_t dtb_size;
Dima Zavin77e41f32013-03-06 16:10:43 -08001194
Dima Zavinc46f8382013-05-03 12:23:06 -07001195 /* the DTB could be unaligned, so extract the header,
1196 * and operate on it separately */
1197 memcpy(&dtb_hdr, dtb, sizeof(struct fdt_header));
1198 if (fdt_check_header((const void *)&dtb_hdr) != 0 ||
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +05301199 fdt_check_header_ext((const void *)&dtb_hdr) != 0 ||
vijay kumare2a5ea82014-06-25 12:24:14 +05301200 ((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) < (uintptr_t)dtb) ||
1201 ((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) > (uintptr_t)kernel_end))
Dima Zavinc46f8382013-05-03 12:23:06 -07001202 break;
1203 dtb_size = fdt_totalsize(&dtb_hdr);
1204
Lijuan Gao9f152862014-08-18 13:45:24 +08001205 dev_tree_compatible(dtb, dtb_size, dt_entry_queue);
Dima Zavinc46f8382013-05-03 12:23:06 -07001206
1207 /* goto the next device tree if any */
1208 dtb += dtb_size;
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001209 }
Dima Zavinc46f8382013-05-03 12:23:06 -07001210
Lijuan Gao9f152862014-08-18 13:45:24 +08001211 best_match_dt_entry = platform_dt_match_best(dt_entry_queue);
1212 if (best_match_dt_entry){
1213 bestmatch_tag = (void *)best_match_dt_entry->offset;
1214 bestmatch_tag_size = best_match_dt_entry->size;
1215 dprintf(INFO, "Best match DTB tags %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1216 best_match_dt_entry->platform_id, best_match_dt_entry->variant_id,
1217 best_match_dt_entry->board_hw_subtype, best_match_dt_entry->soc_rev,
1218 best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],
1219 best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],
1220 best_match_dt_entry->offset, best_match_dt_entry->size);
1221 dprintf(INFO, "Using pmic info 0x%0x/0x%x/0x%x/0x%0x for device 0x%0x/0x%x/0x%x/0x%0x\n",
1222 best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],
1223 best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],
1224 board_pmic_target(0), board_pmic_target(1),
1225 board_pmic_target(2), board_pmic_target(3));
1226 }
1227 /* free queue's memory */
1228 list_for_every_entry(&dt_entry_queue->node, dt_node_tmp1, dt_node, node) {
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001229 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001230 dt_entry_list_delete(dt_node_tmp1);
1231 dt_node_tmp1 = dt_node_tmp2;
1232 }
1233
Shashank Mittalc0f10282013-07-15 14:53:31 -07001234 if(bestmatch_tag) {
Parth Dixitc2f0cb92016-03-10 10:40:14 +05301235 if (check_aboot_addr_range_overlap((uintptr_t)tags, bestmatch_tag_size)) {
1236 dprintf(CRITICAL, "Tags addresses overlap with aboot addresses.\n");
1237 return NULL;
1238 }
Shashank Mittalc0f10282013-07-15 14:53:31 -07001239 memcpy(tags, bestmatch_tag, bestmatch_tag_size);
1240 /* clear out the old DTB magic so kernel doesn't find it */
1241 *((uint32_t *)(kernel + app_dtb_offset)) = 0;
1242 return tags;
1243 }
1244
Dima Zavinc46f8382013-05-03 12:23:06 -07001245 dprintf(CRITICAL, "DTB offset is incorrect, kernel image does not have appended DTB\n");
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001246
David Ng59c4a782015-05-14 15:51:44 -07001247 dprintf(INFO, "Device info 0x%08x/%08x/0x%08x/%u, pmic 0x%0x/0x%x/0x%x/0x%0x\n",
1248 board_platform_id(), board_soc_version(),
1249 board_target_id(), board_hardware_subtype(),
1250 board_pmic_target(0), board_pmic_target(1),
1251 board_pmic_target(2), board_pmic_target(3));
Dima Zavin77e41f32013-03-06 16:10:43 -08001252 return NULL;
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001253}
1254
Joel Kingaa335dc2013-06-03 16:11:08 -07001255/* Returns 0 if the device tree is valid. */
Deepa Dinamani87252952013-09-09 13:58:27 -07001256int dev_tree_validate(struct dt_table *table, unsigned int page_size, uint32_t *dt_hdr_size)
Joel Kingaa335dc2013-06-03 16:11:08 -07001257{
1258 int dt_entry_size;
Channagoud Kadabid87c2772014-06-20 15:41:55 -07001259 uint64_t hdr_size;
Joel Kingaa335dc2013-06-03 16:11:08 -07001260
1261 /* Validate the device tree table header */
1262 if(table->magic != DEV_TREE_MAGIC) {
1263 dprintf(CRITICAL, "ERROR: Bad magic in device tree table \n");
1264 return -1;
1265 }
1266
1267 if (table->version == DEV_TREE_VERSION_V1) {
1268 dt_entry_size = sizeof(struct dt_entry_v1);
1269 } else if (table->version == DEV_TREE_VERSION_V2) {
Lijuan Gao9f152862014-08-18 13:45:24 +08001270 dt_entry_size = sizeof(struct dt_entry_v2);
1271 } else if (table->version == DEV_TREE_VERSION_V3) {
Joel Kingaa335dc2013-06-03 16:11:08 -07001272 dt_entry_size = sizeof(struct dt_entry);
1273 } else {
1274 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
1275 table->version);
1276 return -1;
1277 }
1278
Channagoud Kadabid87c2772014-06-20 15:41:55 -07001279 hdr_size = (uint64_t)table->num_entries * dt_entry_size + DEV_TREE_HEADER_SIZE;
1280
Deepa Dinamani87252952013-09-09 13:58:27 -07001281 /* Roundup to page_size. */
1282 hdr_size = ROUNDUP(hdr_size, page_size);
1283
Channagoud Kadabid87c2772014-06-20 15:41:55 -07001284 if (hdr_size > UINT_MAX)
1285 return -1;
1286 else
1287 *dt_hdr_size = hdr_size & UINT_MAX;
Joel Kingaa335dc2013-06-03 16:11:08 -07001288
1289 return 0;
1290}
1291
Lijuan Gao9f152862014-08-18 13:45:24 +08001292static int platform_dt_absolute_match(struct dt_entry *cur_dt_entry, struct dt_entry_node *dt_list)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001293{
Lijuan Gaof8e95722014-12-23 03:03:12 -05001294 uint32_t cur_dt_hlos_ddr;
Lijuan Gao9f152862014-08-18 13:45:24 +08001295 uint32_t cur_dt_hw_platform;
1296 uint32_t cur_dt_hw_subtype;
1297 uint32_t cur_dt_msm_id;
1298 dt_node *dt_node_tmp = NULL;
Channagoud Kadabi571193a2014-02-05 13:58:49 -08001299
Lijuan Gao9f152862014-08-18 13:45:24 +08001300 /* Platform-id
1301 * bit no |31 24|23 16|15 0|
1302 * |reserved|foundry-id|msm-id|
1303 */
1304 cur_dt_msm_id = (cur_dt_entry->platform_id & 0x0000ffff);
1305 cur_dt_hw_platform = (cur_dt_entry->variant_id & 0x000000ff);
Lijuan Gao0621b862014-09-02 10:02:52 +08001306 cur_dt_hw_subtype = (cur_dt_entry->board_hw_subtype & 0xff);
Lijuan Gao9f152862014-08-18 13:45:24 +08001307
Lijuan Gaof8e95722014-12-23 03:03:12 -05001308 /* Determine the bits 10:8 to check the DT with the DDR Size */
1309 cur_dt_hlos_ddr = (cur_dt_entry->board_hw_subtype & 0x700);
Channagoud Kadabi571193a2014-02-05 13:58:49 -08001310
Lijuan Gao9f152862014-08-18 13:45:24 +08001311 /* 1. must match the msm_id, platform_hw_id, platform_subtype and DDR size
1312 * soc, board major/minor, pmic major/minor must less than board info
1313 * 2. find the matched DTB then return 1
1314 * 3. otherwise return 0
Maria Yu2e2d2c22013-07-03 19:20:33 +08001315 */
Lijuan Gao9f152862014-08-18 13:45:24 +08001316 if((cur_dt_msm_id == (board_platform_id() & 0x0000ffff)) &&
1317 (cur_dt_hw_platform == board_hardware_id()) &&
1318 (cur_dt_hw_subtype == board_hardware_subtype()) &&
Lijuan Gaof8e95722014-12-23 03:03:12 -05001319 (cur_dt_hlos_ddr == (target_get_hlos_subtype() & 0x700)) &&
Lijuan Gao9f152862014-08-18 13:45:24 +08001320 (cur_dt_entry->soc_rev <= board_soc_version()) &&
1321 ((cur_dt_entry->variant_id & 0x00ffff00) <= (board_target_id() & 0x00ffff00)) &&
1322 ((cur_dt_entry->pmic_rev[0] & 0x00ffff00) <= (board_pmic_target(0) & 0x00ffff00)) &&
1323 ((cur_dt_entry->pmic_rev[1] & 0x00ffff00) <= (board_pmic_target(1) & 0x00ffff00)) &&
1324 ((cur_dt_entry->pmic_rev[2] & 0x00ffff00) <= (board_pmic_target(2) & 0x00ffff00)) &&
1325 ((cur_dt_entry->pmic_rev[3] & 0x00ffff00) <= (board_pmic_target(3) & 0x00ffff00))) {
Maria Yu2e2d2c22013-07-03 19:20:33 +08001326
Lijuan Gao9f152862014-08-18 13:45:24 +08001327 dt_node_tmp = dt_entry_list_init();
1328 memcpy((char*)dt_node_tmp->dt_entry_m,(char*)cur_dt_entry, sizeof(struct dt_entry));
1329
1330 dprintf(SPEW, "Add DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1331 dt_node_tmp->dt_entry_m->platform_id, dt_node_tmp->dt_entry_m->variant_id,
1332 dt_node_tmp->dt_entry_m->board_hw_subtype, dt_node_tmp->dt_entry_m->soc_rev,
1333 dt_node_tmp->dt_entry_m->pmic_rev[0], dt_node_tmp->dt_entry_m->pmic_rev[1],
1334 dt_node_tmp->dt_entry_m->pmic_rev[2], dt_node_tmp->dt_entry_m->pmic_rev[3],
1335 dt_node_tmp->dt_entry_m->offset, dt_node_tmp->dt_entry_m->size);
1336
1337 insert_dt_entry_in_queue(dt_list, dt_node_tmp);
1338 return 1;
1339 }
1340 return 0;
1341}
1342
1343static int platform_dt_absolute_compat_match(struct dt_entry_node *dt_list, uint32_t dtb_info) {
1344 struct dt_entry_node *dt_node_tmp1 = NULL;
1345 struct dt_entry_node *dt_node_tmp2 = NULL;
1346 uint32_t current_info = 0;
1347 uint32_t board_info = 0;
1348 uint32_t best_info = 0;
1349 uint32_t current_pmic_model[4] = {0, 0, 0, 0};
1350 uint32_t board_pmic_model[4] = {0, 0, 0, 0};
1351 uint32_t best_pmic_model[4] = {0, 0, 0, 0};
1352 uint32_t delete_current_dt = 0;
1353 uint32_t i;
1354
1355 /* start to select the exact entry
1356 * default to exact match 0, if find current DTB entry info is the same as board info,
1357 * then exact match board info.
1358 */
1359 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1360 if (!dt_node_tmp1){
1361 dprintf(SPEW, "Current node is the end\n");
1362 break;
1363 }
1364 switch(dtb_info) {
1365 case DTB_FOUNDRY:
1366 current_info = ((dt_node_tmp1->dt_entry_m->platform_id) & 0x00ff0000);
Channagoud Kadabi4cffc272014-10-29 11:23:26 -07001367 board_info = board_foundry_id() << 16;
Lijuan Gao9f152862014-08-18 13:45:24 +08001368 break;
1369 case DTB_PMIC_MODEL:
1370 for (i = 0; i < 4; i++) {
1371 current_pmic_model[i] = (dt_node_tmp1->dt_entry_m->pmic_rev[i] & 0xff);
1372 board_pmic_model[i] = (board_pmic_target(i) & 0xff);
1373 }
1374 break;
Lijuan Gaof8e95722014-12-23 03:03:12 -05001375 case DTB_PANEL_TYPE:
1376 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0x1800);
1377 board_info = (target_get_hlos_subtype() & 0x1800);
1378 break;
1379 case DTB_BOOT_DEVICE:
1380 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0xf0000);
1381 board_info = (target_get_hlos_subtype() & 0xf0000);
1382 break;
Lijuan Gao9f152862014-08-18 13:45:24 +08001383 default:
1384 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
1385 dtb_info);
Maria Yuca51ee22013-06-27 21:45:24 +08001386 return 0;
Lijuan Gao9f152862014-08-18 13:45:24 +08001387 }
1388
1389 if (dtb_info == DTB_PMIC_MODEL) {
1390 if ((current_pmic_model[0] == board_pmic_model[0]) &&
1391 (current_pmic_model[1] == board_pmic_model[1]) &&
1392 (current_pmic_model[2] == board_pmic_model[2]) &&
1393 (current_pmic_model[3] == board_pmic_model[3])) {
1394
1395 for (i = 0; i < 4; i++) {
1396 best_pmic_model[i] = current_pmic_model[i];
1397 }
1398 break;
1399 }
1400 } else {
1401 if (current_info == board_info) {
1402 best_info = current_info;
1403 break;
1404 }
1405 }
1406 }
1407
1408 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1409 if (!dt_node_tmp1){
1410 dprintf(SPEW, "Current node is the end\n");
1411 break;
1412 }
1413 switch(dtb_info) {
1414 case DTB_FOUNDRY:
1415 current_info = ((dt_node_tmp1->dt_entry_m->platform_id) & 0x00ff0000);
1416 break;
1417 case DTB_PMIC_MODEL:
1418 for (i = 0; i < 4; i++) {
1419 current_pmic_model[i] = (dt_node_tmp1->dt_entry_m->pmic_rev[i] & 0xff);
1420 }
1421 break;
Lijuan Gaof8e95722014-12-23 03:03:12 -05001422 case DTB_PANEL_TYPE:
1423 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0x1800);
1424 break;
1425 case DTB_BOOT_DEVICE:
1426 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0xf0000);
1427 break;
Lijuan Gao9f152862014-08-18 13:45:24 +08001428 default:
1429 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
1430 dtb_info);
1431 return 0;
1432 }
1433
1434 if (dtb_info == DTB_PMIC_MODEL) {
1435 if ((current_pmic_model[0] != best_pmic_model[0]) ||
1436 (current_pmic_model[1] != best_pmic_model[1]) ||
1437 (current_pmic_model[2] != best_pmic_model[2]) ||
1438 (current_pmic_model[3] != best_pmic_model[3])) {
1439
1440 delete_current_dt = 1;
1441 }
1442 } else {
1443 if (current_info != best_info) {
1444 delete_current_dt = 1;
1445 }
1446 }
1447
1448 if (delete_current_dt) {
1449 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1450 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
1451 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
1452 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
1453 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
1454 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
1455
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001456 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001457 dt_entry_list_delete(dt_node_tmp1);
1458 dt_node_tmp1 = dt_node_tmp2;
1459 delete_current_dt = 0;
Maria Yuca51ee22013-06-27 21:45:24 +08001460 }
1461 }
Maria Yuca51ee22013-06-27 21:45:24 +08001462
Maria Yu2e2d2c22013-07-03 19:20:33 +08001463 return 1;
Maria Yuca51ee22013-06-27 21:45:24 +08001464}
1465
Lijuan Gao9f152862014-08-18 13:45:24 +08001466static int update_dtb_entry_node(struct dt_entry_node *dt_list, uint32_t dtb_info) {
1467 struct dt_entry_node *dt_node_tmp1 = NULL;
1468 struct dt_entry_node *dt_node_tmp2 = NULL;
1469 uint32_t current_info = 0;
1470 uint32_t board_info = 0;
1471 uint32_t best_info = 0;
1472
1473 /* start to select the best entry*/
1474 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1475 if (!dt_node_tmp1){
1476 dprintf(SPEW, "Current node is the end\n");
1477 break;
1478 }
1479 switch(dtb_info) {
1480 case DTB_SOC:
1481 current_info = dt_node_tmp1->dt_entry_m->soc_rev;
1482 board_info = board_soc_version();
1483 break;
1484 case DTB_MAJOR_MINOR:
1485 current_info = ((dt_node_tmp1->dt_entry_m->variant_id) & 0x00ffff00);
1486 board_info = (board_target_id() & 0x00ffff00);
1487 break;
1488 case DTB_PMIC0:
1489 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[0]) & 0x00ffff00);
1490 board_info = (board_pmic_target(0) & 0x00ffff00);
1491 break;
1492 case DTB_PMIC1:
1493 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[1]) & 0x00ffff00);
1494 board_info = (board_pmic_target(1) & 0x00ffff00);
1495 break;
1496 case DTB_PMIC2:
1497 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[2]) & 0x00ffff00);
1498 board_info = (board_pmic_target(2) & 0x00ffff00);
1499 break;
1500 case DTB_PMIC3:
1501 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[3]) & 0x00ffff00);
1502 board_info = (board_pmic_target(3) & 0x00ffff00);
1503 break;
1504 default:
1505 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
1506 dtb_info);
1507 return 0;
1508 }
1509
1510 if (current_info == board_info) {
1511 best_info = current_info;
1512 break;
1513 }
1514 if ((current_info < board_info) && (current_info > best_info)) {
1515 best_info = current_info;
1516 }
1517 if (current_info < best_info) {
1518 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1519 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
1520 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
1521 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
1522 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
1523 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
1524
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001525 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001526 dt_entry_list_delete(dt_node_tmp1);
1527 dt_node_tmp1 = dt_node_tmp2;
1528 }
1529 }
1530
1531 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1532 if (!dt_node_tmp1){
1533 dprintf(SPEW, "Current node is the end\n");
1534 break;
1535 }
1536 switch(dtb_info) {
1537 case DTB_SOC:
1538 current_info = dt_node_tmp1->dt_entry_m->soc_rev;
1539 break;
1540 case DTB_MAJOR_MINOR:
1541 current_info = ((dt_node_tmp1->dt_entry_m->variant_id) & 0x00ffff00);
1542 break;
1543 case DTB_PMIC0:
1544 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[0]) & 0x00ffff00);
1545 break;
1546 case DTB_PMIC1:
1547 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[1]) & 0x00ffff00);
1548 break;
1549 case DTB_PMIC2:
1550 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[2]) & 0x00ffff00);
1551 break;
1552 case DTB_PMIC3:
1553 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[3]) & 0x00ffff00);
1554 break;
1555 default:
1556 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
1557 dtb_info);
1558 return 0;
1559 }
1560
1561 if (current_info != best_info) {
1562 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1563 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
1564 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
1565 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
1566 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
1567 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
1568
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001569 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001570 dt_entry_list_delete(dt_node_tmp1);
1571 dt_node_tmp1 = dt_node_tmp2;
1572 }
1573 }
1574 return 1;
1575}
1576
1577static struct dt_entry *platform_dt_match_best(struct dt_entry_node *dt_list)
1578{
1579 struct dt_entry_node *dt_node_tmp1 = NULL;
1580
1581 /* check Foundry id
1582 * the foundry id must exact match board founddry id, this is compatibility check,
1583 * if couldn't find the exact match from DTB, will exact match 0x0.
1584 */
1585 if (!platform_dt_absolute_compat_match(dt_list, DTB_FOUNDRY))
1586 return NULL;
1587
1588 /* check PMIC model
1589 * the PMIC model must exact match board PMIC model, this is compatibility check,
1590 * if couldn't find the exact match from DTB, will exact match 0x0.
1591 */
1592 if (!platform_dt_absolute_compat_match(dt_list, DTB_PMIC_MODEL))
1593 return NULL;
1594
Lijuan Gaof8e95722014-12-23 03:03:12 -05001595 /* check panel type
1596 * the panel type must exact match board panel type, this is compatibility check,
1597 * if couldn't find the exact match from DTB, will exact match 0x0.
1598 */
1599 if (!platform_dt_absolute_compat_match(dt_list, DTB_PANEL_TYPE))
1600 return NULL;
1601
1602 /* check boot device subtype
1603 * the boot device subtype must exact match board boot device subtype, this is compatibility check,
1604 * if couldn't find the exact match from DTB, will exact match 0x0.
1605 */
1606 if (!platform_dt_absolute_compat_match(dt_list, DTB_BOOT_DEVICE))
1607 return NULL;
1608
Lijuan Gao9f152862014-08-18 13:45:24 +08001609 /* check soc version
1610 * the suitable soc version must less than or equal to board soc version
1611 */
1612 if (!update_dtb_entry_node(dt_list, DTB_SOC))
1613 return NULL;
1614
1615 /*check major and minor version
1616 * the suitable major&minor version must less than or equal to board major&minor version
1617 */
1618 if (!update_dtb_entry_node(dt_list, DTB_MAJOR_MINOR))
1619 return NULL;
1620
1621 /*check pmic info
1622 * the suitable pmic major&minor info must less than or equal to board pmic major&minor version
1623 */
1624 if (!update_dtb_entry_node(dt_list, DTB_PMIC0))
1625 return NULL;
1626 if (!update_dtb_entry_node(dt_list, DTB_PMIC1))
1627 return NULL;
1628 if (!update_dtb_entry_node(dt_list, DTB_PMIC2))
1629 return NULL;
1630 if (!update_dtb_entry_node(dt_list, DTB_PMIC3))
1631 return NULL;
1632
1633 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1634 if (!dt_node_tmp1) {
1635 dprintf(CRITICAL, "ERROR: Couldn't find the suitable DTB!\n");
1636 return NULL;
1637 }
1638 if (dt_node_tmp1->dt_entry_m)
1639 return dt_node_tmp1->dt_entry_m;
1640 }
1641
1642 return NULL;
1643}
1644
1645/* Function to obtain the index information for the correct device tree
1646 * based on the platform data.
1647 * If a matching device tree is found, the information is returned in the
1648 * "dt_entry_info" out parameter and a function value of 0 is returned, otherwise
1649 * a non-zero function value is returned.
1650 */
1651int dev_tree_get_entry_info(struct dt_table *table, struct dt_entry *dt_entry_info)
Maria Yuca51ee22013-06-27 21:45:24 +08001652{
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001653 uint32_t i;
Lijuan Gao9f152862014-08-18 13:45:24 +08001654 unsigned char *table_ptr = NULL;
Joel Kingaa335dc2013-06-03 16:11:08 -07001655 struct dt_entry dt_entry_buf_1;
Lijuan Gao9f152862014-08-18 13:45:24 +08001656 struct dt_entry *cur_dt_entry = NULL;
1657 struct dt_entry *best_match_dt_entry = NULL;
1658 struct dt_entry_v1 *dt_entry_v1 = NULL;
1659 struct dt_entry_v2 *dt_entry_v2 = NULL;
1660 struct dt_entry_node *dt_entry_queue = NULL;
1661 struct dt_entry_node *dt_node_tmp1 = NULL;
1662 struct dt_entry_node *dt_node_tmp2 = NULL;
Maria Yu2e2d2c22013-07-03 19:20:33 +08001663 uint32_t found = 0;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001664
Joel Kingaa335dc2013-06-03 16:11:08 -07001665 if (!dt_entry_info) {
1666 dprintf(CRITICAL, "ERROR: Bad parameter passed to %s \n",
1667 __func__);
1668 return -1;
1669 }
1670
1671 table_ptr = (unsigned char *)table + DEV_TREE_HEADER_SIZE;
1672 cur_dt_entry = &dt_entry_buf_1;
1673 best_match_dt_entry = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +08001674 dt_entry_queue = (struct dt_entry_node *)
1675 malloc(sizeof(struct dt_entry_node));
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001676
Lijuan Gao9f152862014-08-18 13:45:24 +08001677 if (!dt_entry_queue) {
1678 dprintf(CRITICAL, "Out of memory\n");
1679 return -1;
1680 }
1681
1682 list_initialize(&dt_entry_queue->node);
1683 dprintf(INFO, "DTB Total entry: %d, DTB version: %d\n", table->num_entries, table->version);
Maria Yu2e2d2c22013-07-03 19:20:33 +08001684 for(i = 0; found == 0 && i < table->num_entries; i++)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001685 {
Joel Kingaa335dc2013-06-03 16:11:08 -07001686 memset(cur_dt_entry, 0, sizeof(struct dt_entry));
1687 switch(table->version) {
1688 case DEV_TREE_VERSION_V1:
1689 dt_entry_v1 = (struct dt_entry_v1 *)table_ptr;
1690 cur_dt_entry->platform_id = dt_entry_v1->platform_id;
1691 cur_dt_entry->variant_id = dt_entry_v1->variant_id;
1692 cur_dt_entry->soc_rev = dt_entry_v1->soc_rev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001693 cur_dt_entry->board_hw_subtype = (dt_entry_v1->variant_id >> 0x18);
1694 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
1695 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
1696 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
1697 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
Joel Kingaa335dc2013-06-03 16:11:08 -07001698 cur_dt_entry->offset = dt_entry_v1->offset;
1699 cur_dt_entry->size = dt_entry_v1->size;
1700 table_ptr += sizeof(struct dt_entry_v1);
1701 break;
1702 case DEV_TREE_VERSION_V2:
Lijuan Gao9f152862014-08-18 13:45:24 +08001703 dt_entry_v2 = (struct dt_entry_v2*)table_ptr;
1704 cur_dt_entry->platform_id = dt_entry_v2->platform_id;
1705 cur_dt_entry->variant_id = dt_entry_v2->variant_id;
1706 cur_dt_entry->soc_rev = dt_entry_v2->soc_rev;
1707 /* For V2 version of DTBs we have platform version field as part
1708 * of variant ID, in such case the subtype will be mentioned as 0x0
1709 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
1710 * SS -- Subtype
1711 * PM -- Platform major version
1712 * Pm -- Platform minor version
1713 * PH -- Platform hardware CDP/MTP
1714 * In such case to make it compatible with LK algorithm move the subtype
1715 * from variant_id to subtype field
1716 */
1717 if (dt_entry_v2->board_hw_subtype == 0)
1718 cur_dt_entry->board_hw_subtype = (cur_dt_entry->variant_id >> 0x18);
1719 else
1720 cur_dt_entry->board_hw_subtype = dt_entry_v2->board_hw_subtype;
1721 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
1722 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
1723 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
1724 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
1725 cur_dt_entry->offset = dt_entry_v2->offset;
1726 cur_dt_entry->size = dt_entry_v2->size;
1727 table_ptr += sizeof(struct dt_entry_v2);
1728 break;
1729 case DEV_TREE_VERSION_V3:
Joel Kingaa335dc2013-06-03 16:11:08 -07001730 memcpy(cur_dt_entry, (struct dt_entry *)table_ptr,
1731 sizeof(struct dt_entry));
Lijuan Gao9f152862014-08-18 13:45:24 +08001732 /* For V3 version of DTBs we have platform version field as part
1733 * of variant ID, in such case the subtype will be mentioned as 0x0
1734 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
1735 * SS -- Subtype
1736 * PM -- Platform major version
1737 * Pm -- Platform minor version
1738 * PH -- Platform hardware CDP/MTP
1739 * In such case to make it compatible with LK algorithm move the subtype
1740 * from variant_id to subtype field
1741 */
1742 if (cur_dt_entry->board_hw_subtype == 0)
1743 cur_dt_entry->board_hw_subtype = (cur_dt_entry->variant_id >> 0x18);
1744
Joel Kingaa335dc2013-06-03 16:11:08 -07001745 table_ptr += sizeof(struct dt_entry);
1746 break;
1747 default:
1748 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
1749 table->version);
Lijuan Gao9f152862014-08-18 13:45:24 +08001750 free(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001751 return -1;
1752 }
1753
Lijuan Gao9f152862014-08-18 13:45:24 +08001754 /* DTBs must match the platform_id, platform_hw_id, platform_subtype and DDR size.
1755 * The satisfactory DTBs are stored in dt_entry_queue
1756 */
1757 platform_dt_absolute_match(cur_dt_entry, dt_entry_queue);
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -08001758
Lijuan Gao9f152862014-08-18 13:45:24 +08001759 }
1760 best_match_dt_entry = platform_dt_match_best(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001761 if (best_match_dt_entry) {
1762 *dt_entry_info = *best_match_dt_entry;
Maria Yu2e2d2c22013-07-03 19:20:33 +08001763 found = 1;
1764 }
1765
1766 if (found != 0) {
Sundarajan Srinivasan763c0db2014-05-20 17:08:36 -07001767 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 -07001768 dt_entry_info->platform_id, dt_entry_info->soc_rev,
1769 dt_entry_info->variant_id, dt_entry_info->board_hw_subtype,
Lijuan Gao9f152862014-08-18 13:45:24 +08001770 board_platform_id(), board_soc_version(),
1771 board_target_id(), board_hardware_subtype());
1772 if (dt_entry_info->pmic_rev[0] == 0 && dt_entry_info->pmic_rev[0] == 0 &&
1773 dt_entry_info->pmic_rev[0] == 0 && dt_entry_info->pmic_rev[0] == 0) {
1774 dprintf(SPEW, "No maintain pmic info in DTB, device pmic info is 0x%0x/0x%x/0x%x/0x%0x\n",
1775 board_pmic_target(0), board_pmic_target(1),
1776 board_pmic_target(2), board_pmic_target(3));
1777 } else {
1778 dprintf(INFO, "Using pmic info 0x%0x/0x%x/0x%x/0x%0x for device 0x%0x/0x%x/0x%x/0x%0x\n",
1779 dt_entry_info->pmic_rev[0], dt_entry_info->pmic_rev[1],
1780 dt_entry_info->pmic_rev[2], dt_entry_info->pmic_rev[3],
1781 board_pmic_target(0), board_pmic_target(1),
1782 board_pmic_target(2), board_pmic_target(3));
1783 }
Joel Kingaa335dc2013-06-03 16:11:08 -07001784 return 0;
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -08001785 }
1786
Lijuan Gao9f152862014-08-18 13:45:24 +08001787 dprintf(CRITICAL, "ERROR: Unable to find suitable device tree for device (%u/0x%08x/0x%08x/%u)\n",
1788 board_platform_id(), board_soc_version(),
1789 board_target_id(), board_hardware_subtype());
1790
1791 list_for_every_entry(&dt_entry_queue->node, dt_node_tmp1, dt_node, node) {
1792 /* free node memory */
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001793 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001794 dt_entry_list_delete(dt_node_tmp1);
1795 dt_node_tmp1 = dt_node_tmp2;
1796 }
1797 free(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001798 return -1;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001799}
1800
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001801/* Function to add the first RAM partition info to the device tree.
1802 * Note: The function replaces the reg property in the "/memory" node
1803 * with the addr and size provided.
1804 */
1805int dev_tree_add_first_mem_info(uint32_t *fdt, uint32_t offset, uint32_t addr, uint32_t size)
1806{
1807 int ret;
1808
1809 ret = fdt_setprop_u32(fdt, offset, "reg", addr);
1810
1811 if (ret)
1812 {
1813 dprintf(CRITICAL, "Failed to add the memory information addr: %d\n",
1814 ret);
1815 }
1816
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001817 ret = fdt_appendprop_u32(fdt, offset, "reg", size);
1818
1819 if (ret)
1820 {
1821 dprintf(CRITICAL, "Failed to add the memory information size: %d\n",
1822 ret);
1823 }
1824
1825 return ret;
1826}
1827
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001828static 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 -07001829{
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001830 int len;
1831 uint32_t *valp;
1832 int ret;
1833 uint32_t offset;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001834
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001835 mem_node->offset = mem_node_offset;
1836
1837 /* Get offset of the root node */
1838 ret = fdt_path_offset(fdt, "/");
1839 if (ret < 0)
1840 {
1841 dprintf(CRITICAL, "Could not find memory node.\n");
1842 return ret;
1843 }
1844
1845 offset = ret;
1846
1847 /* Find the #address-cells size. */
1848 valp = (uint32_t*)fdt_getprop(fdt, offset, "#address-cells", &len);
Lijuan Gaoae0927b2014-07-18 17:16:16 +08001849 if (len <= 0 || !valp)
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001850 {
1851 if (len == -FDT_ERR_NOTFOUND)
1852 {
1853 /* Property not found.
1854 * Assume standard sizes.
1855 */
1856 mem_node->addr_cell_size = 2;
1857 dprintf(CRITICAL, "Using default #addr_cell_size: %u\n", mem_node->addr_cell_size);
1858 }
1859 else
1860 {
1861 dprintf(CRITICAL, "Error finding the #address-cells property\n");
1862 return len;
1863 }
1864 }
1865 else
1866 mem_node->addr_cell_size = fdt32_to_cpu(*valp);
1867
1868 /* Find the #size-cells size. */
1869 valp = (uint32_t*)fdt_getprop(fdt, offset, "#size-cells", &len);
Lijuan Gaoae0927b2014-07-18 17:16:16 +08001870 if (len <= 0 || !valp)
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001871 {
1872 if (len == -FDT_ERR_NOTFOUND)
1873 {
1874 /* Property not found.
1875 * Assume standard sizes.
1876 */
1877 mem_node->size_cell_size = 1;
1878 dprintf(CRITICAL, "Using default #size_cell_size: %u\n", mem_node->size_cell_size);
1879 }
1880 else
1881 {
1882 dprintf(CRITICAL, "Error finding the #size-cells property\n");
1883 return len;
1884 }
1885 }
1886 else
1887 mem_node->size_cell_size = fdt32_to_cpu(*valp);
1888
1889 return 0;
1890}
1891
1892static void dev_tree_update_memory_node(uint32_t offset)
1893{
1894 mem_node.offset = offset;
1895 mem_node.addr_cell_size = 1;
1896 mem_node.size_cell_size = 1;
1897}
1898
1899/* Function to add the subsequent RAM partition info to the device tree. */
1900int dev_tree_add_mem_info(void *fdt, uint32_t offset, uint64_t addr, uint64_t size)
1901{
1902 int ret = 0;
1903
1904 if(smem_get_ram_ptable_version() >= 1)
1905 {
1906 ret = dev_tree_query_memory_cell_sizes(fdt, &mem_node, offset);
1907 if (ret < 0)
1908 {
1909 dprintf(CRITICAL, "Could not find #address-cells and #size-cells properties: ret %d\n", ret);
1910 return ret;
1911 }
1912
1913 }
1914 else
1915 {
1916 dev_tree_update_memory_node(offset);
1917 }
1918
1919 if (!(mem_node.mem_info_cnt))
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001920 {
1921 /* Replace any other reg prop in the memory node. */
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001922
1923 /* cell_size is the number of 32 bit words used to represent an address/length in the device tree.
1924 * memory node in DT can be either 32-bit(cell-size = 1) or 64-bit(cell-size = 2).So when updating
1925 * the memory node in the device tree, we write one word or two words based on cell_size = 1 or 2.
1926 */
1927
1928 if(mem_node.addr_cell_size == 2)
1929 {
1930 ret = fdt_setprop_u32(fdt, mem_node.offset, "reg", addr >> 32);
1931 if(ret)
1932 {
1933 dprintf(CRITICAL, "ERROR: Could not set prop reg for memory node\n");
1934 return ret;
1935 }
1936
1937 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1938 if(ret)
1939 {
1940 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1941 return ret;
1942 }
1943 }
1944 else
1945 {
1946 ret = fdt_setprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1947 if(ret)
1948 {
1949 dprintf(CRITICAL, "ERROR: Could not set prop reg for memory node\n");
1950 return ret;
1951 }
1952 }
1953
1954 mem_node.mem_info_cnt = 1;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001955 }
1956 else
1957 {
1958 /* Append the mem info to the reg prop for subsequent nodes. */
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001959 if(mem_node.addr_cell_size == 2)
1960 {
1961 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", addr >> 32);
1962 if(ret)
1963 {
1964 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1965 return ret;
1966 }
1967 }
1968
1969 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1970 if(ret)
1971 {
1972 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1973 return ret;
1974 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001975 }
1976
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001977 if(mem_node.size_cell_size == 2)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001978 {
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001979 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", size>>32);
1980 if(ret)
1981 {
1982 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1983 return ret;
1984 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001985 }
1986
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001987 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)size);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001988
1989 if (ret)
1990 {
1991 dprintf(CRITICAL, "Failed to add the memory information size: %d\n",
1992 ret);
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001993 return ret;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001994 }
1995
1996 return ret;
1997}
1998
1999/* Top level function that updates the device tree. */
2000int update_device_tree(void *fdt, const char *cmdline,
2001 void *ramdisk, uint32_t ramdisk_size)
2002{
2003 int ret = 0;
2004 uint32_t offset;
lijuangc76a7632017-12-07 14:37:56 +08002005#if ENABLE_KASLRSEED_SUPPORT
2006 uintptr_t kaslrseed;
2007#endif
Mayank Grover2533aab2018-02-23 18:06:07 +05302008 uint32_t cmdline_len = 0;
2009
2010 if (cmdline)
2011 cmdline_len = strlen(cmdline);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002012
2013 /* Check the device tree header */
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +05302014 ret = fdt_check_header(fdt) || fdt_check_header_ext(fdt);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002015 if (ret)
2016 {
2017 dprintf(CRITICAL, "Invalid device tree header \n");
2018 return ret;
2019 }
2020
P.V. Phani Kumar9cd95102016-03-09 12:35:23 +05302021 if (check_aboot_addr_range_overlap((uint32_t)fdt,
Mayank Grover2533aab2018-02-23 18:06:07 +05302022 (fdt_totalsize(fdt) + DTB_PAD_SIZE + cmdline_len))) {
P.V. Phani Kumar9cd95102016-03-09 12:35:23 +05302023 dprintf(CRITICAL, "Error: Fdt addresses overlap with aboot addresses.\n");
2024 return ret;
2025 }
2026
Deepa Dinamani1c970732013-04-19 14:23:01 -07002027 /* Add padding to make space for new nodes and properties. */
Mayank Grover2533aab2018-02-23 18:06:07 +05302028 ret = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + DTB_PAD_SIZE + cmdline_len);
Deepa Dinamani1c970732013-04-19 14:23:01 -07002029 if (ret!= 0)
2030 {
2031 dprintf(CRITICAL, "Failed to move/resize dtb buffer: %d\n", ret);
2032 return ret;
2033 }
2034
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002035 /* Get offset of the memory node */
2036 ret = fdt_path_offset(fdt, "/memory");
2037 if (ret < 0)
2038 {
2039 dprintf(CRITICAL, "Could not find memory node.\n");
2040 return ret;
2041 }
2042
2043 offset = ret;
2044
2045 ret = target_dev_tree_mem(fdt, offset);
2046 if(ret)
2047 {
2048 dprintf(CRITICAL, "ERROR: Cannot update memory node\n");
2049 return ret;
2050 }
2051
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002052 /* Get offset of the chosen node */
2053 ret = fdt_path_offset(fdt, "/chosen");
2054 if (ret < 0)
2055 {
2056 dprintf(CRITICAL, "Could not find chosen node.\n");
2057 return ret;
2058 }
2059
2060 offset = ret;
Maria Yuabde9542014-07-07 14:49:34 +08002061 if (cmdline)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002062 {
Maria Yuabde9542014-07-07 14:49:34 +08002063 /* Adding the cmdline to the chosen node */
2064 ret = fdt_appendprop_string(fdt, offset, (const char*)"bootargs", (const void*)cmdline);
2065 if (ret)
2066 {
2067 dprintf(CRITICAL, "ERROR: Cannot update chosen node [bootargs]\n");
2068 return ret;
2069 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002070 }
2071
lijuangc76a7632017-12-07 14:37:56 +08002072#if ENABLE_KASLRSEED_SUPPORT
2073 if (!scm_random(&kaslrseed, sizeof(kaslrseed))) {
2074 /* Adding Kaslr Seed to the chosen node */
2075 ret = fdt_appendprop_u64 (fdt, offset, (const char *)"kaslr-seed", (uint64_t)kaslrseed);
2076 if (ret)
2077 dprintf(CRITICAL, "ERROR: Cannot update chosen node [kaslr-seed] - 0x%x\n", ret);
2078 else
2079 dprintf(CRITICAL, "kaslr-Seed is added to chosen node\n");
2080 } else {
2081 dprintf(CRITICAL, "ERROR: Cannot generate Kaslr Seed\n");
2082 }
2083#endif
2084
Joonwoo Parka5b5f492014-02-13 18:24:48 -08002085 if (ramdisk_size) {
2086 /* Adding the initrd-start to the chosen node */
2087 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-start",
2088 (uint32_t)ramdisk);
2089 if (ret)
2090 {
2091 dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-start]\n");
2092 return ret;
2093 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002094
Joonwoo Parka5b5f492014-02-13 18:24:48 -08002095 /* Adding the initrd-end to the chosen node */
2096 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-end",
2097 ((uint32_t)ramdisk + ramdisk_size));
2098 if (ret)
2099 {
2100 dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-end]\n");
2101 return ret;
2102 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002103 }
2104
Kishor PK536904a2017-07-13 17:18:59 +05302105#if ENABLE_BOOTDEVICE_MOUNT
2106 /* Update fstab node */
2107 dprintf(SPEW, "Start of fstab node update:%zu ms\n", platform_get_sclk_count());
2108 if (update_fstab_node(fdt) != 0) {
2109 dprintf(CRITICAL, "ERROR: Cannot update fstab node\n");
2110 return ret;
2111 }
2112 dprintf(SPEW, "End of fstab node update:%zu ms\n", platform_get_sclk_count());
2113#endif
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002114 fdt_pack(fdt);
2115
Channagoud Kadabiffaea422014-12-05 15:45:41 -08002116#if ENABLE_PARTIAL_GOODS_SUPPORT
2117 update_partial_goods_dtb_nodes(fdt);
2118#endif
2119
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002120 return ret;
2121}
Kishor PK536904a2017-07-13 17:18:59 +05302122
2123#if ENABLE_BOOTDEVICE_MOUNT
2124/*Update device tree for fstab node */
2125static int update_fstab_node(void *fdt)
2126{
2127 int ret = 0;
2128 int str_len = 0;
2129 int parent_offset = 0;
2130 int subnode_offset = 0;
2131 int prop_length = 0;
2132 int prefix_string_len = 0;
2133 char *node_name = NULL;
2134 char *boot_dev_buf = NULL;
2135 char *new_str = NULL;
2136 char *prefix_str = NULL;
2137 char *suffix_str = NULL;
2138 const struct fdt_property *prop = NULL;
2139
2140 /* Find the parent node */
2141 parent_offset = fdt_path_offset(fdt, fstab_table.parent_node);
2142 if (parent_offset < 0) {
2143 dprintf(CRITICAL, "Failed to get parent node: fstab error: %d\n", parent_offset);
2144 return -1;
2145 }
2146 dprintf(SPEW, "Node: %s found.\n", fdt_get_name(fdt, parent_offset, NULL));
2147
2148 /* Get boot device type */
2149 boot_dev_buf = (char *) malloc(sizeof(char) * BOOT_DEV_MAX_LEN);
2150 if (!boot_dev_buf) {
2151 dprintf(CRITICAL, "Failed to allocate memory for boot device\n");
2152 return -1;
2153 }
2154
2155 new_str = (char *) malloc(sizeof(char) * NODE_PROPERTY_MAX_LEN);
2156 if (!new_str) {
2157 dprintf(CRITICAL, "Failed to allocate memory for node property string\n");
2158 return -1;
2159 }
2160
2161
2162 platform_boot_dev_cmdline(boot_dev_buf);
2163
2164 /* Get properties of all sub nodes */
2165 for (subnode_offset = fdt_first_subnode(fdt, parent_offset); subnode_offset >= 0; subnode_offset = fdt_next_subnode(fdt, subnode_offset)) {
2166 prop = fdt_get_property(fdt, subnode_offset, fstab_table.node_prop, &prop_length);
2167 node_name = (char *)(uintptr_t)fdt_get_name(fdt, subnode_offset, NULL);
2168 if (!prop) {
2169 dprintf(CRITICAL, "Property:%s is not found for sub node:%s\n", fstab_table.node_prop, node_name);
2170 } else {
2171 dprintf(CRITICAL, "Property:%s found for sub node:%s\tproperty:%s\n", fstab_table.node_prop, node_name, prop->data);
2172 /* Pointer to fdt 'dev' property string that needs to update based on the 'androidboot.bootdevice' */
2173 memset(new_str, 0, NODE_PROPERTY_MAX_LEN);
2174 prefix_str = (char *)prop->data;
2175 if (strlen(prefix_str) > NODE_PROPERTY_MAX_LEN) {
2176 dprintf(CRITICAL, "Property string length is greater than node property max length\n");
2177 continue;
2178 }
2179 suffix_str = strstr(prefix_str, fstab_table.device_path_id);
2180 if (!suffix_str) {
2181 dprintf(CRITICAL, "Property is not proper to update\n");
2182 continue;
2183 }
2184 suffix_str += strlen(fstab_table.device_path_id);
2185 prefix_string_len = strlen(prefix_str) - (strlen(suffix_str) - 1);
2186 suffix_str = strstr((suffix_str + 1), "/");
2187 str_len = strlcpy(new_str, prefix_str, prefix_string_len);
2188 if (!str_len) {
2189 dprintf(CRITICAL, "Property length is not proper to update\n");
2190 continue;
2191 }
2192 str_len = strlcat(new_str, boot_dev_buf, strlen(prefix_str));
2193 if (!str_len) {
2194 dprintf(CRITICAL, "Property length is not proper to update\n");
2195 continue;
2196 }
2197 str_len = strlcat(new_str, suffix_str, strlen(prefix_str));
2198 if (!str_len) {
2199 dprintf(CRITICAL, "Property length is not proper to update\n");
2200 continue;
2201 }
2202 /* Update the new property in the memory */
2203 memscpy(prefix_str, strlen(prefix_str), new_str, strlen(new_str) + 1);
2204 /* Update the property with new value */
2205 ret = fdt_setprop(fdt, subnode_offset, fstab_table.node_prop, (const void *)prefix_str, strlen(prefix_str) + 1);
2206 if(ret) {
2207 dprintf(CRITICAL, "Failed to update the node with new property\n");
2208 continue;
2209 }
2210 dprintf(CRITICAL, "Updated %s with new property %s\n", node_name, prop->data);
2211 }
2212 }
2213 if (boot_dev_buf)
2214 free(boot_dev_buf);
2215 if (new_str)
2216 free(new_str);
2217 return ret;
2218}
2219#endif