blob: 024b5c363dd48cf147dce444f13cbdfa10441275 [file] [log] [blame]
Mayank Grover324a9772019-05-08 16:06:19 +05301/* Copyright (c) 2012-2015,2017-2019 The Linux Foundation. All rights reserved.
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27*/
28
29#include <libfdt.h>
30#include <dev_tree.h>
31#include <lib/ptable.h>
32#include <malloc.h>
33#include <qpic_nand.h>
34#include <stdlib.h>
35#include <string.h>
36#include <platform.h>
37#include <board.h>
Lijuan Gao9f152862014-08-18 13:45:24 +080038#include <list.h>
39#include <kernel/thread.h>
Mayank Grover1b6da5d2017-12-19 16:05:46 +053040#include <kernel/event.h>
vijay kumar4f4405f2014-08-08 11:49:53 +053041#include <target.h>
Channagoud Kadabiffaea422014-12-05 15:45:41 -080042#include <partial_goods.h>
Kishor PK536904a2017-07-13 17:18:59 +053043#include <boot_device.h>
44#include <platform.h>
lijuangc76a7632017-12-07 14:37:56 +080045#include <scm.h>
Mayank Grover1b6da5d2017-12-19 16:05:46 +053046#include <partition_parser.h>
47#include <libufdt_sysdeps.h>
48#include <ufdt_overlay.h>
Mayank Grover302432a2017-12-08 17:18:58 +053049#include <boot_stats.h>
Mayank Grover8f46a892018-09-10 13:24:59 +053050#include <verifiedboot.h>
Kishor PK536904a2017-07-13 17:18:59 +053051
Kishor PK536904a2017-07-13 17:18:59 +053052#define NODE_PROPERTY_MAX_LEN 64
Mayank Grover1b6da5d2017-12-19 16:05:46 +053053#define ADD_OF(a, b) (UINT_MAX - b > a) ? (a + b) : UINT_MAX
54#define ADDR_ALIGNMENT 16
55/** 512KB stack **/
56#define DTBO_STACK_SIZE (524288)
57#define MAX_DTBO_SZ 2097152
58
59static bool dtbo_needed = true;
60static void *board_dtb = NULL;
61static void *soc_dtb = NULL;
62static void *soc_dtb_hdr = NULL;
63static void *final_dtb_hdr = NULL;
64static event_t dtbo_event;
65
Mayank Grover1b6da5d2017-12-19 16:05:46 +053066dtbo_error ret = DTBO_SUCCESS;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -070067
Joel Kingaa335dc2013-06-03 16:11:08 -070068struct dt_entry_v1
69{
70 uint32_t platform_id;
71 uint32_t variant_id;
72 uint32_t soc_rev;
73 uint32_t offset;
74 uint32_t size;
75};
76
Mayank Grovera9ffe802019-06-03 14:08:40 +053077#if ENABLE_BOOTDEVICE_MOUNT || DYNAMIC_PARTITION_SUPPORT
Kishor PK536904a2017-07-13 17:18:59 +053078/* Look up table for fstab node */
79struct fstab_node
80{
81 const char *parent_node;
82 const char *node_prop;
83 const char *device_path_id;
84};
85
Mayank Grovera9ffe802019-06-03 14:08:40 +053086static struct fstab_node dynamic_fstab_table =
87{
88 "/firmware/android/fstab", "status", ""
89};
90
Kishor PK536904a2017-07-13 17:18:59 +053091static struct fstab_node fstab_table =
92{
93 "/firmware/android/fstab", "dev", "/soc/"
94};
95#endif
96
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -070097static struct dt_mem_node_info mem_node;
Lijuan Gao9f152862014-08-18 13:45:24 +080098static int platform_dt_absolute_match(struct dt_entry *cur_dt_entry, struct dt_entry_node *dt_list);
99static struct dt_entry *platform_dt_match_best(struct dt_entry_node *dt_list);
100static int update_dtb_entry_node(struct dt_entry_node *dt_list, uint32_t dtb_info);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700101extern int target_is_emmc_boot(void);
102extern uint32_t target_dev_tree_mem(void *fdt, uint32_t memory_node_offset);
Kishor PK536904a2017-07-13 17:18:59 +0530103static int update_fstab_node(void *fdt);
104
Deepa Dinamanic55f01b2013-05-30 14:05:56 -0700105/* TODO: This function needs to be moved to target layer to check violations
106 * against all the other regions as well.
107 */
Vijay Kumar Pendoti9c002ad2016-03-09 13:52:45 +0530108extern int check_aboot_addr_range_overlap(uintptr_t start, uint32_t size);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700109
lijuang0cce8bf2018-08-23 10:56:42 +0800110static int dtbo_idx = INVALID_PTN;
111int get_dtbo_idx (void)
112{
113 return dtbo_idx;
114}
115
Parth Dixit30e1a762019-07-08 21:37:33 +0530116static int dtb_idx = INVALID_PTN;
117int get_dtb_idx (void)
118{
119 return dtb_idx;
120}
121
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +0530122int fdt_check_header_ext(const void *fdt)
123{
124 uintptr_t fdt_start, fdt_end;
125 fdt_start = (uintptr_t)fdt;
126 if(fdt_start + fdt_totalsize(fdt) < fdt_start)
127 {
128 dprintf(CRITICAL,"Integer over in fdt header %s\t%d",__func__,__LINE__);
129 return FDT_ERR_BADOFFSET;
130 }
131 fdt_end = fdt_start + fdt_totalsize(fdt);
132
133 if (((uint64_t)fdt_start + (uint64_t)fdt_off_dt_struct(fdt) + (uint64_t)fdt_size_dt_struct(fdt)) > UINT_MAX)
134 return FDT_ERR_BADOFFSET;
135
136 if ((fdt_start + fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt)) > fdt_end)
137 return FDT_ERR_BADOFFSET;
138
139 if (((uint64_t)fdt_start + (uint64_t)fdt_off_dt_strings(fdt) + (uint64_t)fdt_size_dt_strings(fdt)) > UINT_MAX)
140 return FDT_ERR_BADOFFSET;
141
142 if ((fdt_start + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)) > fdt_end)
143 return FDT_ERR_BADOFFSET;
144
145 return 0;
146}
147
Shashank Mittalc0f10282013-07-15 14:53:31 -0700148/* Returns soc version if platform id and hardware id matches
149 otherwise return 0xFFFFFFFF */
150#define INVALID_SOC_REV_ID 0XFFFFFFFF
Lijuan Gao9f152862014-08-18 13:45:24 +0800151
152/* Add function to allocate dt entry list, used for recording
153* the entry which conform to platform_dt_absolute_match()
154*/
155static struct dt_entry_node *dt_entry_list_init(void)
156{
157 struct dt_entry_node *dt_node_member = NULL;
158
159 dt_node_member = (struct dt_entry_node *)
160 malloc(sizeof(struct dt_entry_node));
161
162 ASSERT(dt_node_member);
163
164 list_clear_node(&dt_node_member->node);
165 dt_node_member->dt_entry_m = (struct dt_entry *)
166 malloc(sizeof(struct dt_entry));
167 ASSERT(dt_node_member->dt_entry_m);
168
169 memset(dt_node_member->dt_entry_m ,0 ,sizeof(struct dt_entry));
170 return dt_node_member;
171}
172
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530173/*
174 * Function to validate dtbo image.
175 * return: TRUE or FALSE.
176 */
Mayank Groverb61c0c22018-09-04 15:09:32 +0530177dtbo_error load_validate_dtbo_image(void **dtbo_buf, uint32_t *dtbo_image_sz)
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530178{
179 uint64_t dtbo_total_size = 0;
Mayank Groverb61c0c22018-09-04 15:09:32 +0530180 static void *dtbo_image_buf = NULL;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530181 unsigned int dtbo_image_buf_size;
182 unsigned int dtbo_partition_size;
Mayank Groverb61c0c22018-09-04 15:09:32 +0530183 unsigned long long ptn, boot_img_sz;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530184 int index = INVALID_PTN;
185 int page_size = mmc_page_size();
186 struct dtbo_table_hdr *dtbo_table_header = NULL;
187 dtbo_error ret = DTBO_SUCCESS;
Mayank Groverb61c0c22018-09-04 15:09:32 +0530188 static bool dtbo_loaded = false;
189 static unsigned long long ptn_size = 0;
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530190 uint32_t recovery_dtbo_size = 0;
191 void *recovery_appended_dtbo = NULL;
Mayank Groverb61c0c22018-09-04 15:09:32 +0530192
193 /* If dtbo loaded skip loading */
194 if (dtbo_loaded)
195 goto out;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530196
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530197 get_recovery_dtbo_info(&recovery_dtbo_size, &recovery_appended_dtbo);
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530198
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530199 /* Intialize dtbo for recovery header v1 */
200 if (recovery_dtbo_size && recovery_appended_dtbo) {
201 dtbo_image_buf = recovery_appended_dtbo;
202 dtbo_partition_size = recovery_dtbo_size;
203 ptn_size = recovery_dtbo_size;
204 } else {
205 index = partition_get_index("dtbo");
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530206
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530207
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530208 /* Immediately return if dtbo is not supported */
209 if (index == INVALID_PTN)
210 {
211 ret = DTBO_NOT_SUPPORTED;
212 goto out;
213 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530214
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530215 ptn = partition_get_offset(index);
216 if(!ptn)
217 {
218 dprintf(CRITICAL, "ERROR: dtbo parition failed to get offset. \n");
219 ret = DTBO_ERROR;
220 goto out;
221 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530222
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530223 ptn_size = partition_get_size(index);
224 if (ptn_size > MAX_SUPPORTED_DTBO_IMG_BUF)
225 {
226 dprintf(CRITICAL, "ERROR: dtbo parition size is greater than supported.\n");
227 ret = DTBO_ERROR;
228 goto out;
229 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530230
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530231 /*
232 Read dtbo image into scratch region after kernel image.
233 dtbo_image_buf_size = total_scratch_region_size - boot_img_sz
234 */
235 boot_img_sz = partition_get_size(partition_get_index("boot"));
236 if (!boot_img_sz)
237 {
238 dprintf(CRITICAL, "ERROR: Unable to get boot partition size\n");
239 ret = DTBO_NOT_SUPPORTED;
240 goto out;
241 }
242
243 dtbo_image_buf_size = target_get_max_flash_size() - boot_img_sz;
244 dtbo_partition_size = ptn_size + ADDR_ALIGNMENT;
245 dtbo_partition_size = ROUND_TO_PAGE(dtbo_partition_size, (page_size - 1)); /* Maximum dtbo size possible */
246 if (dtbo_partition_size == UINT_MAX ||
247 dtbo_image_buf_size < dtbo_partition_size)
248 {
249 dprintf(CRITICAL, "ERROR: Invalid DTBO partition size\n");
250 ret = DTBO_NOT_SUPPORTED;
251 goto out;
252 }
253
254 mmc_set_lun(partition_get_lun(index));
255 /* read dtbo at last 10MB of scratch */
256 dtbo_image_buf = target_get_scratch_address() +
257 (target_get_max_flash_size() - DTBO_IMG_BUF);
258 dtbo_image_buf =
Mayank Grover8f46a892018-09-10 13:24:59 +0530259 (void *)ROUND_TO_PAGE((addr_t)dtbo_image_buf, (ADDR_ALIGNMENT-1));
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530260 if(dtbo_image_buf == (void *)UINT_MAX)
261 {
262 dprintf(CRITICAL, "ERROR: Invalid DTBO image buf addr\n");
263 ret = DTBO_NOT_SUPPORTED;
264 goto out;
265 }
266
Mayank Grover8f46a892018-09-10 13:24:59 +0530267 /* Add offset for salt buffer for verification */
268 dtbo_image_buf += SALT_BUFF_OFFSET;
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530269 /* Read dtbo partition with header */
270 if (mmc_read(ptn, (uint32_t *)(dtbo_image_buf), dtbo_partition_size))
271 {
272 dprintf(CRITICAL, "ERROR: dtbo partition mmc read failure \n");
273 ret = DTBO_ERROR;
274 goto out;
275 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530276 }
277
278 /* validate the dtbo image, before reading complete image */
279 dtbo_table_header = (struct dtbo_table_hdr *)dtbo_image_buf;
280
281 /*Check for dtbo magic*/
282 if (fdt32_to_cpu(dtbo_table_header->magic) != DTBO_TABLE_MAGIC)
283 {
284 dprintf(CRITICAL, "dtbo header magic mismatch %x, with %x\n",
285 fdt32_to_cpu(dtbo_table_header->magic), DTBO_TABLE_MAGIC);
286 ret = DTBO_ERROR;
287 goto out;
288 }
289
290 /*Check for dtbo image table size*/
291 if (fdt32_to_cpu(dtbo_table_header->hdr_size) != sizeof(struct dtbo_table_hdr))
292 {
293 dprintf(CRITICAL, "dtbo table header size got corrupted\n");
294 ret = DTBO_ERROR;
295 goto out;
296 }
297
298 /*Check for dt entry size of dtbo image*/
299 if (fdt32_to_cpu(dtbo_table_header->dt_entry_size) != sizeof(struct dtbo_table_entry))
300 {
301 dprintf(CRITICAL, "dtbo table dt entry size got corrupted\n");
302 ret = DTBO_ERROR;
303 goto out;
304 }
305
306 /*Total size of dtbo */
307 dtbo_total_size = fdt32_to_cpu(dtbo_table_header->total_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 /* Total size of dtbo entries */
316 dtbo_total_size = fdt32_to_cpu(dtbo_table_header->dt_entry_count) *
317 fdt32_to_cpu(dtbo_table_header->dt_entry_size);
318 if (dtbo_total_size > dtbo_partition_size || dtbo_total_size == 0)
319 {
320 dprintf(CRITICAL, "dtbo table total size exceeded the dtbo buffer allocated\n");
321 ret = DTBO_ERROR;
322 goto out;
323 }
324
325 /* Offset should be less than image size */
326 if (fdt32_to_cpu(dtbo_table_header->dt_entry_offset) > dtbo_partition_size)
327 {
328 dprintf(CRITICAL, "dtbo offset exceeds the dtbo buffer allocated\n");
329 ret = DTBO_ERROR;
330 goto out;
331 }
332
333 /* Offset + total size is less than image size */
334 if (dtbo_total_size + fdt32_to_cpu(dtbo_table_header->dt_entry_offset) > dtbo_partition_size)
335 {
336 dprintf(CRITICAL, "dtbo size exceeded the dtbo buffer allocated\n");
337 ret = DTBO_ERROR;
338 }
339
340out:
Mayank Groverb61c0c22018-09-04 15:09:32 +0530341 if (ret == DTBO_SUCCESS)
342 {
343 *dtbo_buf = dtbo_image_buf;
344 *dtbo_image_sz = (uint32_t)ptn_size;
345 dtbo_loaded = true;
346 }
347 else
348 {
349 *dtbo_buf = NULL;
350 *dtbo_image_sz = 0;
351 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530352 return ret;
353}
354
355static bool check_all_bits_set(uint32_t matchdt_value)
356{
357 return (matchdt_value & ALL_BITS_SET) == (ALL_BITS_SET);
358}
359
360/* Dt selection table for quick reference
361 | SNO | Dt Property | CDT Property | Exact | Best | Default |
362 |-----+---------------+-----------------+-------+------+---------+
363 | | qcom, msm-id | | | | |
364 | | | PlatformId | Y | N | N |
365 | | | SocRev | N | Y | N |
366 | | | FoundryId | Y | N | 0 |
367 | | qcom,board-id | | | | |
368 | | | VariantId | Y | N | N |
369 | | | VariantMajor | N | Y | N |
370 | | | VariantMinor | N | Y | N |
371 | | | PlatformSubtype | Y | N | 0 |
372 | | qcom,pmic-id | | | | |
373 | | | PmicModelId | Y | N | 0 |
374 | | | PmicMetalRev | N | Y | N |
375 | | | PmicLayerRev | N | Y | N |
376 | | | PmicVariantRev | N | Y | N |
377*/
378
lijuang0cce8bf2018-08-23 10:56:42 +0800379static 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 +0530380{
381 int board_id_len;
382 int platform_id_len = 0;
383 int pmic_id_len;
384 int root_offset = 0;
385 void *dtb = current_dtb_info->dtb;
386 uint32_t idx;
387 const char *platform_prop = NULL;
388 const char *board_prop = NULL;
389 const char *pmic_prop = NULL;
lijuang0cce8bf2018-08-23 10:56:42 +0800390 boolean find_best_match = false;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530391
392 current_dtb_info->dt_match_val = 0;
393 root_offset = fdt_path_offset(dtb, "/");
394 if (root_offset < 0) {
395 dprintf(CRITICAL, "ERROR: Unable to locate root node\n");
lijuang0cce8bf2018-08-23 10:56:42 +0800396 return false;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530397 }
398
399 /* Get the msm-id prop from DTB and find best match */
400 platform_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,msm-id", &platform_id_len);
401 if (platform_prop && (platform_id_len > 0) && (!(platform_id_len % PLAT_ID_SIZE))) {
402 /*Compare msm-id of the dtb vs board*/
403 current_dtb_info->dt_platform_id = fdt32_to_cpu(((struct plat_id *)platform_prop)->platform_id);
404 dprintf(SPEW, "Board SOC ID = %x | DT SOC ID = %x\n", (board_platform_id() & SOC_MASK),
405 (current_dtb_info->dt_platform_id & SOC_MASK));
406 if ((board_platform_id() & SOC_MASK) == (current_dtb_info->dt_platform_id & SOC_MASK)) {
407 current_dtb_info->dt_match_val |= BIT(SOC_MATCH);
408 } else {
409 dprintf(SPEW, "qcom,msm-id does not match\n");
410 /* If soc doesn't match, don't select dtb */
411 current_dtb_info->dt_match_val = BIT(NONE_MATCH);
412 goto cleanup;
413 }
414 /*Compare soc rev of the dtb vs board*/
415 current_dtb_info->dt_soc_rev = fdt32_to_cpu(((struct plat_id *)platform_prop)->soc_rev);
416 dprintf(SPEW, "Board SOC Rev = %x | DT SOC Rev =%x\n", board_soc_version(),
417 current_dtb_info->dt_soc_rev);
418 if (current_dtb_info->dt_soc_rev == board_soc_version()) {
419 current_dtb_info->dt_match_val |= BIT(VERSION_EXACT_MATCH);
420 } else if (current_dtb_info->dt_soc_rev < board_soc_version()) {
421 current_dtb_info->dt_match_val |= BIT(VERSION_BEST_MATCH);
422 } else if (current_dtb_info->dt_soc_rev) {
423 dprintf(SPEW, "SOC version does not match\n");
424 }
425 /*Compare Foundry Id of the dtb vs Board*/
426 current_dtb_info->dt_foundry_id = fdt32_to_cpu(((struct plat_id *)platform_prop)->platform_id) & FOUNDRY_ID_MASK;
427 dprintf (SPEW, "Board Foundry id = %x | DT Foundry id = %x\n", (board_foundry_id() << PLATFORM_FOUNDRY_SHIFT), current_dtb_info->dt_foundry_id);
428 if (current_dtb_info->dt_foundry_id == (board_foundry_id() << PLATFORM_FOUNDRY_SHIFT)) {
429 current_dtb_info->dt_match_val |= BIT (FOUNDRYID_EXACT_MATCH);
430 } else if (current_dtb_info->dt_foundry_id == 0 ){
431 current_dtb_info->dt_match_val |= BIT (FOUNDRYID_DEFAULT_MATCH);
432 } else {
433 dprintf(SPEW, "soc foundry does not match\n");
434 /* If soc doesn't match, don't select dtb */
435 current_dtb_info->dt_match_val = BIT(NONE_MATCH);
436 goto cleanup;
437 }
438 } else {
439 dprintf(SPEW, "qcom,msm-id does not exist (or) is (%d) not a multiple of (%d)\n", platform_id_len, PLAT_ID_SIZE);
440 }
441
442 /* Get the properties like variant id, subtype from DTB and compare the DTB vs Board */
443 board_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,board-id", &board_id_len);
444 if (board_prop && (board_id_len > 0) && (!(board_id_len % BOARD_ID_SIZE))) {
445 current_dtb_info->dt_variant_id = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id);
446 current_dtb_info->dt_platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->platform_subtype);
447 if (current_dtb_info->dt_platform_subtype == 0)
448 current_dtb_info->dt_platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id) >> PLATFORM_SUBTYPE_SHIFT_ID;
449
450 dprintf(SPEW, "Board variant id = %x | DT variant id = %x\n",board_hardware_id(), current_dtb_info->dt_variant_id);
451
452 current_dtb_info->dt_variant_major = current_dtb_info->dt_variant_id & VARIANT_MAJOR_MASK;
453 current_dtb_info->dt_variant_minor = current_dtb_info->dt_variant_id & VARIANT_MINOR_MASK;
454 current_dtb_info->dt_variant_id = current_dtb_info->dt_variant_id & VARIANT_MASK;
455
456 if (current_dtb_info->dt_variant_id == board_hardware_id()) {
457 current_dtb_info->dt_match_val |= BIT(VARIANT_MATCH);
458 } else if (current_dtb_info->dt_variant_id) {
459 dprintf(SPEW, "qcom,board-id doesnot match\n");
460 /* If board variant doesn't match, don't select dtb */
461 current_dtb_info->dt_match_val = BIT(NONE_MATCH);
462 goto cleanup;
463 }
464
465 if (current_dtb_info->dt_variant_major == (board_target_id() & VARIANT_MAJOR_MASK)) {
466 current_dtb_info->dt_match_val |= BIT(VARIANT_MAJOR_EXACT_MATCH);
467 } else if (current_dtb_info->dt_variant_major < (board_target_id() & VARIANT_MAJOR_MASK)) {
468 current_dtb_info->dt_match_val |= BIT(VARIANT_MAJOR_BEST_MATCH);
469 } else if (current_dtb_info->dt_variant_major) {
470 dprintf(SPEW, "qcom,board-id major version doesnot match\n");
471 }
472
473 if (current_dtb_info->dt_variant_minor == (board_target_id() & VARIANT_MINOR_MASK)) {
474 current_dtb_info->dt_match_val |= BIT(VARIANT_MINOR_EXACT_MATCH);
475 } else if (current_dtb_info->dt_variant_minor < (board_target_id() & VARIANT_MINOR_MASK)) {
476 current_dtb_info->dt_match_val |= BIT(VARIANT_MINOR_BEST_MATCH);
477 } else if (current_dtb_info->dt_variant_minor) {
478 dprintf(SPEW, "qcom,board-id minor version doesnot match\n");
479 }
480
481 dprintf(SPEW, "Board platform subtype = %x | DT platform subtype = %x\n",
482 board_hardware_subtype(), current_dtb_info->dt_platform_subtype);
483 if (current_dtb_info->dt_platform_subtype == board_hardware_subtype()) {
484 current_dtb_info->dt_match_val |= BIT(SUBTYPE_EXACT_MATCH);
485 } else if (current_dtb_info->dt_platform_subtype == 0) {
486 current_dtb_info->dt_match_val |= BIT(SUBTYPE_DEFAULT_MATCH);
487 } else if (current_dtb_info->dt_platform_subtype) {
488 dprintf(SPEW, "subtype id doesnot match\n");
489 /* If board platform doesn't match, don't select dtb */
490 current_dtb_info->dt_match_val = BIT(NONE_MATCH);
491 goto cleanup;
492 }
493 } else {
494 dprintf(SPEW, "qcom,board-id does not exist (or)(%d) is not a multiple of (%d)\n",
495 board_id_len, BOARD_ID_SIZE);
496 }
497
498 /* Get the pmic property from DTB then compare the DTB vs Board */
499 pmic_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,pmic-id", &pmic_id_len);
500 if (pmic_prop && (pmic_id_len > 0) && (!(pmic_id_len % sizeof(struct pmic_id))))
501 {
502 pmic_info curr_pmic_info;
503 pmic_info best_pmic_info;
504 unsigned int pmic_entry_indx;
505 unsigned int pmic_entries_count;
506
507 /* Find all pmic entries count */
508 pmic_entries_count = pmic_id_len/sizeof(struct pmic_id);
509
510 memset(&best_pmic_info, 0, sizeof(pmic_info));
511 for (pmic_entry_indx = 0; pmic_entry_indx < pmic_entries_count; pmic_entry_indx++)
512 {
513 memset(&curr_pmic_info, 0, sizeof(pmic_info));
514
515 /* Read all pmic info */
516 /* Compare with board pmic */
517 for (idx = 0; idx < MAX_PMIC_IDX; idx++)
518 {
519 curr_pmic_info.dt_pmic_model[idx] =
520 fdt32_to_cpu (((struct pmic_id *)pmic_prop)->pmic_version[idx]);
521 dprintf(SPEW, "pmic_data[%u]:%x\n", idx, curr_pmic_info.dt_pmic_model[idx]);
522 curr_pmic_info.dt_pmic_rev[idx] =
523 curr_pmic_info.dt_pmic_model[idx] & PMIC_REV_MASK;
524 curr_pmic_info.dt_pmic_model[idx] =
525 curr_pmic_info.dt_pmic_model[idx] & PMIC_MODEL_MASK;
526
527 /* Compare with board pmic information & Update bit mask */
528 if (curr_pmic_info.dt_pmic_model[idx] == (board_pmic_target(idx) & PMIC_MODEL_MASK))
529 curr_pmic_info.dt_match_val |= BIT (PMIC_MATCH_EXACT_MODEL_IDX0 + idx * PMIC_SHIFT_IDX);
530 else if (curr_pmic_info.dt_pmic_model[idx] == 0)
531 curr_pmic_info.dt_match_val |= BIT (PMIC_MATCH_DEFAULT_MODEL_IDX0 + idx * PMIC_SHIFT_IDX);
532 else
533 {
534 curr_pmic_info.dt_match_val |= BIT (NONE_MATCH);
535 dprintf(SPEW, "PMIC Model doesn't match\n");
536 break; /* go to next pmic entry */
537 }
538
539 if (curr_pmic_info.dt_pmic_rev[idx] == (board_pmic_target(idx) & PMIC_REV_MASK))
540 curr_pmic_info.dt_match_val |= BIT(PMIC_MATCH_EXACT_REV_IDX0 + idx * PMIC_SHIFT_IDX);
541 else if (curr_pmic_info.dt_pmic_rev[idx] < (board_pmic_target(idx) & PMIC_REV_MASK))
542 curr_pmic_info.dt_match_val |= BIT(PMIC_MATCH_BEST_REV_IDX0 + idx * PMIC_SHIFT_IDX);
lijuangf1b8e1d2018-03-01 14:40:37 +0800543 else {
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530544 dprintf(SPEW, "PMIC revision doesn't match\n");
545 break; /* go to next pmic entry */
lijuangf1b8e1d2018-03-01 14:40:37 +0800546 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530547 }
548
549 dprintf(SPEW, "Bestpmicinfo.dtmatchval : %x | cur_pmic_info.dtmatchval: %x\n",
550 best_pmic_info.dt_match_val, curr_pmic_info.dt_match_val);
551
552 /* Update best pmic info, if required */
553 if(best_pmic_info.dt_match_val < curr_pmic_info.dt_match_val)
554 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
555 else if (best_pmic_info.dt_match_val == curr_pmic_info.dt_match_val)
556 {
557 if (best_pmic_info.dt_pmic_rev[PMIC_IDX0] < curr_pmic_info.dt_pmic_rev[PMIC_IDX0])
558 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
559 else if (best_pmic_info.dt_pmic_rev[PMIC_IDX1] < curr_pmic_info.dt_pmic_rev[PMIC_IDX1])
560 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
561 else if (best_pmic_info.dt_pmic_rev[PMIC_IDX2] < curr_pmic_info.dt_pmic_rev[PMIC_IDX2])
562 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
563 else if (best_pmic_info.dt_pmic_rev[PMIC_IDX3] < curr_pmic_info.dt_pmic_rev[PMIC_IDX3])
564 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
565 }
566
567 /* Increment to next pmic entry */
568 pmic_prop += sizeof (struct pmic_id);
569 }
570
571 dprintf(SPEW, "Best pmic info 0x%0x/0x%x/0x%x/0x%0x for current dt\n",
572 best_pmic_info.dt_pmic_model[PMIC_IDX0],
573 best_pmic_info.dt_pmic_model[PMIC_IDX1],
574 best_pmic_info.dt_pmic_model[PMIC_IDX2],
575 best_pmic_info.dt_pmic_model[PMIC_IDX3]);
576
577 current_dtb_info->dt_match_val |= best_pmic_info.dt_match_val;
578 current_dtb_info->dt_pmic_rev[PMIC_IDX0] = best_pmic_info.dt_pmic_rev[PMIC_IDX0];
579 current_dtb_info->dt_pmic_model[PMIC_IDX0] = best_pmic_info.dt_pmic_model[PMIC_IDX0];
580 current_dtb_info->dt_pmic_rev[PMIC_IDX1] = best_pmic_info.dt_pmic_rev[PMIC_IDX1];
581 current_dtb_info->dt_pmic_model[PMIC_IDX1] = best_pmic_info.dt_pmic_model[PMIC_IDX1];
582 current_dtb_info->dt_pmic_rev[PMIC_IDX2] = best_pmic_info.dt_pmic_rev[PMIC_IDX2];
583 current_dtb_info->dt_pmic_model[PMIC_IDX2] = best_pmic_info.dt_pmic_model[PMIC_IDX2];
584 current_dtb_info->dt_pmic_rev[PMIC_IDX3] = best_pmic_info.dt_pmic_rev[PMIC_IDX3];
585 current_dtb_info->dt_pmic_model[PMIC_IDX3] = best_pmic_info.dt_pmic_model[PMIC_IDX3];
586 }
587 else
588 {
589 dprintf(SPEW, "qcom,pmic-id does not exit (or) is (%d) not a multiple of (%d)\n",
590 pmic_id_len, PMIC_ID_SIZE);
591 }
592
593cleanup:
594 if (current_dtb_info->dt_match_val & BIT(exact_match)) {
lijuang0cce8bf2018-08-23 10:56:42 +0800595 if (best_dtb_info->dt_match_val < current_dtb_info->dt_match_val) {
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530596 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
lijuang0cce8bf2018-08-23 10:56:42 +0800597 find_best_match = true;
598 } else if (best_dtb_info->dt_match_val == current_dtb_info->dt_match_val) {
599 find_best_match = true;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530600 if (best_dtb_info->dt_soc_rev < current_dtb_info->dt_soc_rev)
601 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
602 else if (best_dtb_info->dt_variant_major < current_dtb_info->dt_variant_major)
603 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
604 else if (best_dtb_info->dt_variant_minor < current_dtb_info->dt_variant_minor)
605 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
606 else if (best_dtb_info->dt_pmic_rev[0] < current_dtb_info->dt_pmic_rev[0])
607 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
608 else if (best_dtb_info->dt_pmic_rev[1] < current_dtb_info->dt_pmic_rev[1])
609 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
610 else if (best_dtb_info->dt_pmic_rev[2] < current_dtb_info->dt_pmic_rev[2])
611 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
612 else if (best_dtb_info->dt_pmic_rev[3] < current_dtb_info->dt_pmic_rev[3])
613 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
lijuang0cce8bf2018-08-23 10:56:42 +0800614 else
615 find_best_match = false;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530616 }
617 }
lijuang0cce8bf2018-08-23 10:56:42 +0800618
619 return find_best_match;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530620}
621
622void *get_soc_dtb(void *kernel, uint32_t kernel_size, uint32_t dtb_offset)
623{
624 uintptr_t kernel_end_offset = (uintptr_t)kernel + kernel_size;
625 void *dtb = NULL;
626 struct fdt_header dtb_header;
627 uint32_t dtb_size = 0;
628 dt_info cur_dtb_info = {0};
629 dt_info best_dtb_info = {0};
Parth Dixit30e1a762019-07-08 21:37:33 +0530630 uint32_t dtb_cnt = 0;
631 boolean find_best_dtb = false;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530632
633 if (!dtb_offset){
634 dprintf(CRITICAL, "DTB offset is NULL\n");
635 return NULL;
636 }
637 if (((uintptr_t)kernel + (uintptr_t)dtb_offset) < (uintptr_t)kernel) {
638 return NULL;
639 }
640 dtb = kernel + dtb_offset;
641 while (((uintptr_t)dtb + sizeof(struct fdt_header)) < (uintptr_t)kernel_end_offset) {
642 /* the DTB could be unaligned, so extract the header,
643 * and operate on it separately */
644 memscpy(&dtb_header, sizeof(struct fdt_header), dtb, sizeof(struct fdt_header));
645 dtb_size = fdt_totalsize((const void *)&dtb_header);
646 if (fdt_check_header((const void *)&dtb_header) != 0 ||
647 fdt_check_header_ext((void *)&dtb_header) != 0 ||
648 ((uintptr_t)dtb + dtb_size < (uintptr_t)dtb) ||
649 ((uintptr_t)dtb + dtb_size > (uintptr_t)kernel_end_offset))
650 break;
651
652 cur_dtb_info.dtb = dtb;
Parth Dixit30e1a762019-07-08 21:37:33 +0530653 find_best_dtb = dtb_read_find_match(&cur_dtb_info, &best_dtb_info, SOC_MATCH);
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530654 if (cur_dtb_info.dt_match_val) {
655 if (cur_dtb_info.dt_match_val & BIT(SOC_MATCH)) {
656 if (check_all_bits_set(cur_dtb_info.dt_match_val)) {
657 dprintf(CRITICAL, "Exact DTB match found. dtbo search is not required\n");
658 dtbo_needed = false;
659 }
660 }
661 }
Parth Dixit30e1a762019-07-08 21:37:33 +0530662
663 dprintf(SPEW, "dtb count = %u local_soc_dt_match val = %x\n", dtb_cnt, best_dtb_info.dt_match_val);
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530664 dtb += dtb_size;
Parth Dixit30e1a762019-07-08 21:37:33 +0530665
666 if (find_best_dtb) {
667 dtb_idx = dtb_cnt;
668 }
669 dtb_cnt++;
670
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530671 }
672 if (!best_dtb_info.dtb) {
673 dprintf(CRITICAL, "No match found for soc dtb type\n");
674 return NULL;
675 }
676 return best_dtb_info.dtb;
677}
678
679void *get_board_dtb(void *dtbo_image_buf)
680{
681 struct dtbo_table_hdr *dtbo_table_header = dtbo_image_buf;
682 struct dtbo_table_entry *dtb_table_entry = NULL;
683 uint32_t dtbo_count = 0;
684 void *board_dtb = NULL;
685 uint32_t dtbo_table_entries_count = 0;
686 uint32_t first_dtbo_table_entry_offset = 0;
687 struct fdt_header dtb_header;
688 uint32_t dtb_size = 0;
689 dt_info cur_dtb_info = {0};
690 dt_info best_dtb_info = {0};
lijuang0cce8bf2018-08-23 10:56:42 +0800691 boolean find_best_dtb = false;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530692
693 if (!dtbo_image_buf) {
694 dprintf(CRITICAL, "dtbo image buffer is NULL\n");
695 return NULL;
696 }
697
698 first_dtbo_table_entry_offset = fdt32_to_cpu(dtbo_table_header->dt_entry_offset);
699 if ((uintptr_t)dtbo_image_buf > ((uintptr_t)dtbo_image_buf + (uintptr_t)first_dtbo_table_entry_offset))
700 {
701 dprintf(CRITICAL, "dtbo table entry offset is invalid\n");
702 return NULL;
703 }
704 dtb_table_entry = (struct dtbo_table_entry *)(dtbo_image_buf + first_dtbo_table_entry_offset);
705 dtbo_table_entries_count = fdt32_to_cpu(dtbo_table_header->dt_entry_count);
706 for (dtbo_count = 0; dtbo_count < dtbo_table_entries_count; dtbo_count++) {
707 board_dtb = dtbo_image_buf + fdt32_to_cpu(dtb_table_entry->dt_offset);
708 /* The DTB could be unaligned, so extract the header,
709 * and operate on it separately */
710 memscpy(&dtb_header, sizeof(struct fdt_header), board_dtb, sizeof(struct fdt_header));
711 dtb_size = fdt_totalsize((const void *)&dtb_header);
712 if (fdt_check_header((const void *)&dtb_header) != 0 ||
713 fdt_check_header_ext((void *)&dtb_header) != 0 ||
714 ((uintptr_t)board_dtb + dtb_size < (uintptr_t)board_dtb)) {
715 dprintf(CRITICAL, "No valid board dtb found\n");
716 break;
717 }
718 dprintf(SPEW, "Valid board dtb is found\n");
719 cur_dtb_info.dtb = board_dtb;
lijuang0cce8bf2018-08-23 10:56:42 +0800720 find_best_dtb = dtb_read_find_match(&cur_dtb_info, &best_dtb_info, VARIANT_MATCH);
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530721 dprintf(SPEW, "dtbo count = %u local_board_dt_match =%x\n",dtbo_count, cur_dtb_info.dt_match_val);
722 dtb_table_entry++;
lijuang0cce8bf2018-08-23 10:56:42 +0800723
724 if (find_best_dtb) {
725 dtbo_idx = dtbo_count;
726 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530727 }
728 if (!best_dtb_info.dtb) {
729 dprintf(CRITICAL, "Unable to find the board dtb\n");
730 return NULL;
731 }
732 return best_dtb_info.dtb;
733}
734
Lijuan Gao9f152862014-08-18 13:45:24 +0800735static void insert_dt_entry_in_queue(struct dt_entry_node *dt_list, struct dt_entry_node *dt_node_member)
736{
737 list_add_tail(&dt_list->node, &dt_node_member->node);
738}
739
740static void dt_entry_list_delete(struct dt_entry_node *dt_node_member)
741{
742 if (list_in_list(&dt_node_member->node)) {
743 list_delete(&dt_node_member->node);
744 free(dt_node_member->dt_entry_m);
745 free(dt_node_member);
746 }
747}
748
749static int dev_tree_compatible(void *dtb, uint32_t dtb_size, struct dt_entry_node *dtb_list)
Dima Zavinc46f8382013-05-03 12:23:06 -0700750{
751 int root_offset;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700752 const void *prop = NULL;
753 const char *plat_prop = NULL;
754 const char *board_prop = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800755 const char *pmic_prop = NULL;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700756 char *model = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800757 struct dt_entry *cur_dt_entry;
758 struct dt_entry *dt_entry_array = NULL;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700759 struct board_id *board_data = NULL;
760 struct plat_id *platform_data = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800761 struct pmic_id *pmic_data = NULL;
Dima Zavinc46f8382013-05-03 12:23:06 -0700762 int len;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700763 int len_board_id;
764 int len_plat_id;
765 int min_plat_id_len = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800766 int len_pmic_id;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700767 uint32_t dtb_ver;
768 uint32_t num_entries = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800769 uint32_t i, j, k, n;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700770 uint32_t msm_data_count;
771 uint32_t board_data_count;
Lijuan Gao9f152862014-08-18 13:45:24 +0800772 uint32_t pmic_data_count;
Parth Dixit30e1a762019-07-08 21:37:33 +0530773 uint32_t dtb_count = 0;;
Dima Zavinc46f8382013-05-03 12:23:06 -0700774
775 root_offset = fdt_path_offset(dtb, "/");
776 if (root_offset < 0)
777 return false;
778
779 prop = fdt_getprop(dtb, root_offset, "model", &len);
780 if (prop && len > 0) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700781 model = (char *) malloc(sizeof(char) * len);
782 ASSERT(model);
783 strlcpy(model, prop, len);
Dima Zavinc46f8382013-05-03 12:23:06 -0700784 } else {
vijay kumar89d36d82014-06-30 19:32:18 +0530785 dprintf(INFO, "model does not exist in device tree\n");
Dima Zavinc46f8382013-05-03 12:23:06 -0700786 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800787 /* Find the pmic-id prop from DTB , if pmic-id is present then
788 * the DTB is version 3, otherwise find the board-id prop from DTB ,
789 * if board-id is present then the DTB is version 2 */
790 pmic_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,pmic-id", &len_pmic_id);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700791 board_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,board-id", &len_board_id);
Lijuan Gao9f152862014-08-18 13:45:24 +0800792 if (pmic_prop && (len_pmic_id > 0) && board_prop && (len_board_id > 0)) {
793 if ((len_pmic_id % PMIC_ID_SIZE) || (len_board_id % BOARD_ID_SIZE))
794 {
795 dprintf(CRITICAL, "qcom,pmic-id(%d) or qcom,board-id(%d) in device tree is not a multiple of (%d %d)\n",
796 len_pmic_id, len_board_id, PMIC_ID_SIZE, BOARD_ID_SIZE);
797 return false;
798 }
799 dtb_ver = DEV_TREE_VERSION_V3;
800 min_plat_id_len = PLAT_ID_SIZE;
801 } else if (board_prop && len_board_id > 0) {
vijay kumar89d36d82014-06-30 19:32:18 +0530802 if (len_board_id % BOARD_ID_SIZE)
803 {
804 dprintf(CRITICAL, "qcom,board-id in device tree is (%d) not a multiple of (%d)\n",
805 len_board_id, BOARD_ID_SIZE);
806 return false;
807 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700808 dtb_ver = DEV_TREE_VERSION_V2;
809 min_plat_id_len = PLAT_ID_SIZE;
Lijuan Gao9f152862014-08-18 13:45:24 +0800810 } else {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700811 dtb_ver = DEV_TREE_VERSION_V1;
812 min_plat_id_len = DT_ENTRY_V1_SIZE;
813 }
814
815 /* Get the msm-id prop from DTB */
816 plat_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,msm-id", &len_plat_id);
817 if (!plat_prop || len_plat_id <= 0) {
Dima Zavinc46f8382013-05-03 12:23:06 -0700818 dprintf(INFO, "qcom,msm-id entry not found\n");
819 return false;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700820 } else if (len_plat_id % min_plat_id_len) {
821 dprintf(INFO, "qcom,msm-id in device tree is (%d) not a multiple of (%d)\n",
822 len_plat_id, min_plat_id_len);
Dima Zavinc46f8382013-05-03 12:23:06 -0700823 return false;
824 }
Dima Zavinc46f8382013-05-03 12:23:06 -0700825
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700826 /*
827 * If DTB version is '1' look for <x y z> pair in the DTB
828 * x: platform_id
829 * y: variant_id
830 * z: SOC rev
831 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800832 if (dtb_ver == DEV_TREE_VERSION_V1) {
833 cur_dt_entry = (struct dt_entry *)
834 malloc(sizeof(struct dt_entry));
Dima Zavinc46f8382013-05-03 12:23:06 -0700835
Lijuan Gao9f152862014-08-18 13:45:24 +0800836 if (!cur_dt_entry) {
837 dprintf(CRITICAL, "Out of memory\n");
838 return false;
839 }
840 memset(cur_dt_entry, 0, sizeof(struct dt_entry));
841
842 while (len_plat_id) {
843 cur_dt_entry->platform_id = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->platform_id);
844 cur_dt_entry->variant_id = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->variant_id);
845 cur_dt_entry->soc_rev = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->soc_rev);
846 cur_dt_entry->board_hw_subtype =
847 fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->variant_id) >> 0x18;
848 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
849 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
850 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
851 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
852 cur_dt_entry->offset = (uint32_t)dtb;
853 cur_dt_entry->size = dtb_size;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700854
855 dprintf(SPEW, "Found an appended flattened device tree (%s - %u %u 0x%x)\n",
Lijuan Gao9f152862014-08-18 13:45:24 +0800856 *model ? model : "unknown",
857 cur_dt_entry->platform_id, cur_dt_entry->variant_id, cur_dt_entry->soc_rev);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700858
Lijuan Gao9f152862014-08-18 13:45:24 +0800859 if (platform_dt_absolute_match(cur_dt_entry, dtb_list)) {
860 dprintf(SPEW, "Device tree exact match the board: <%u %u 0x%x> != <%u %u 0x%x>\n",
861 cur_dt_entry->platform_id,
862 cur_dt_entry->variant_id,
863 cur_dt_entry->soc_rev,
864 board_platform_id(),
865 board_hardware_id(),
866 board_soc_version());
867
868 } else {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700869 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 +0800870 cur_dt_entry->platform_id,
871 cur_dt_entry->variant_id,
872 cur_dt_entry->soc_rev,
873 board_platform_id(),
874 board_hardware_id(),
875 board_soc_version());
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700876 plat_prop += DT_ENTRY_V1_SIZE;
877 len_plat_id -= DT_ENTRY_V1_SIZE;
878 continue;
879 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700880 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800881 free(cur_dt_entry);
882
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700883 }
884 /*
Lijuan Gao9f152862014-08-18 13:45:24 +0800885 * If DTB Version is '3' then we have split DTB with board & msm data & pmic
886 * populated saperately in board-id & msm-id & pmic-id prop respectively.
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700887 * Extract the data & prepare a look up table
888 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800889 else if (dtb_ver == DEV_TREE_VERSION_V2 || dtb_ver == DEV_TREE_VERSION_V3) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700890 board_data_count = (len_board_id / BOARD_ID_SIZE);
891 msm_data_count = (len_plat_id / PLAT_ID_SIZE);
Lijuan Gao9f152862014-08-18 13:45:24 +0800892 /* If dtb version is v2.0, the pmic_data_count will be <= 0 */
893 pmic_data_count = (len_pmic_id / PMIC_ID_SIZE);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700894
Lijuan Gao9f152862014-08-18 13:45:24 +0800895 /* If we are using dtb v3.0, then we have split board, msm & pmic data in the DTB
896 * If we are using dtb v2.0, then we have split board & msmdata in the DTB
897 */
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700898 board_data = (struct board_id *) malloc(sizeof(struct board_id) * (len_board_id / BOARD_ID_SIZE));
899 ASSERT(board_data);
900 platform_data = (struct plat_id *) malloc(sizeof(struct plat_id) * (len_plat_id / PLAT_ID_SIZE));
901 ASSERT(platform_data);
Lijuan Gao9f152862014-08-18 13:45:24 +0800902 if (dtb_ver == DEV_TREE_VERSION_V3) {
903 pmic_data = (struct pmic_id *) malloc(sizeof(struct pmic_id) * (len_pmic_id / PMIC_ID_SIZE));
904 ASSERT(pmic_data);
905 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700906 i = 0;
907
908 /* Extract board data from DTB */
Lijuan Gao9f152862014-08-18 13:45:24 +0800909 for(i = 0 ; i < board_data_count; i++) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700910 board_data[i].variant_id = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id);
911 board_data[i].platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->platform_subtype);
Lijuan Gao9f152862014-08-18 13:45:24 +0800912 /* For V2/V3 version of DTBs we have platform version field as part
913 * of variant ID, in such case the subtype will be mentioned as 0x0
914 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
915 * SS -- Subtype
916 * PM -- Platform major version
917 * Pm -- Platform minor version
918 * PH -- Platform hardware CDP/MTP
919 * In such case to make it compatible with LK algorithm move the subtype
920 * from variant_id to subtype field
921 */
922 if (board_data[i].platform_subtype == 0)
923 board_data[i].platform_subtype =
924 fdt32_to_cpu(((struct board_id *)board_prop)->variant_id) >> 0x18;
925
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700926 len_board_id -= sizeof(struct board_id);
927 board_prop += sizeof(struct board_id);
928 }
929
930 /* Extract platform data from DTB */
Lijuan Gao9f152862014-08-18 13:45:24 +0800931 for(i = 0 ; i < msm_data_count; i++) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700932 platform_data[i].platform_id = fdt32_to_cpu(((struct plat_id *)plat_prop)->platform_id);
933 platform_data[i].soc_rev = fdt32_to_cpu(((struct plat_id *)plat_prop)->soc_rev);
934 len_plat_id -= sizeof(struct plat_id);
935 plat_prop += sizeof(struct plat_id);
936 }
937
Lijuan Gao9f152862014-08-18 13:45:24 +0800938 if (dtb_ver == DEV_TREE_VERSION_V3 && pmic_prop) {
939 /* Extract pmic data from DTB */
940 for(i = 0 ; i < pmic_data_count; i++) {
941 pmic_data[i].pmic_version[0]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[0]);
942 pmic_data[i].pmic_version[1]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[1]);
943 pmic_data[i].pmic_version[2]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[2]);
944 pmic_data[i].pmic_version[3]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[3]);
945 len_pmic_id -= sizeof(struct pmic_id);
946 pmic_prop += sizeof(struct pmic_id);
947 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700948
Lijuan Gao9f152862014-08-18 13:45:24 +0800949 /* We need to merge board & platform data into dt entry structure */
950 num_entries = msm_data_count * board_data_count * pmic_data_count;
951 } else {
952 /* We need to merge board & platform data into dt entry structure */
953 num_entries = msm_data_count * board_data_count;
954 }
vijay kumar89d36d82014-06-30 19:32:18 +0530955
Lijuan Gao9f152862014-08-18 13:45:24 +0800956 if ((((uint64_t)msm_data_count * (uint64_t)board_data_count * (uint64_t)pmic_data_count) !=
957 msm_data_count * board_data_count * pmic_data_count) ||
958 (((uint64_t)msm_data_count * (uint64_t)board_data_count) != msm_data_count * board_data_count)) {
959
960 free(board_data);
961 free(platform_data);
962 if (pmic_data)
963 free(pmic_data);
964 if (model)
965 free(model);
966 return false;
967 }
968
969 dt_entry_array = (struct dt_entry*) malloc(sizeof(struct dt_entry) * num_entries);
970 ASSERT(dt_entry_array);
971
972 /* If we have '<X>; <Y>; <Z>' as platform data & '<A>; <B>; <C>' as board data.
973 * Then dt entry should look like
974 * <X ,A >;<X, B>;<X, C>;
975 * <Y ,A >;<Y, B>;<Y, C>;
976 * <Z ,A >;<Z, B>;<Z, C>;
977 */
978 i = 0;
979 k = 0;
980 n = 0;
Parth Dixit30e1a762019-07-08 21:37:33 +0530981 dtb_count++;
Lijuan Gao9f152862014-08-18 13:45:24 +0800982 for (i = 0; i < msm_data_count; i++) {
983 for (j = 0; j < board_data_count; j++) {
Parth Dixit30e1a762019-07-08 21:37:33 +0530984 dt_entry_array[k].idx = dtb_count;
985 if (dtb_ver == DEV_TREE_VERSION_V3 && pmic_prop){
Lijuan Gao9f152862014-08-18 13:45:24 +0800986 for (n = 0; n < pmic_data_count; n++) {
987 dt_entry_array[k].platform_id = platform_data[i].platform_id;
988 dt_entry_array[k].soc_rev = platform_data[i].soc_rev;
989 dt_entry_array[k].variant_id = board_data[j].variant_id;
990 dt_entry_array[k].board_hw_subtype = board_data[j].platform_subtype;
991 dt_entry_array[k].pmic_rev[0]= pmic_data[n].pmic_version[0];
992 dt_entry_array[k].pmic_rev[1]= pmic_data[n].pmic_version[1];
993 dt_entry_array[k].pmic_rev[2]= pmic_data[n].pmic_version[2];
994 dt_entry_array[k].pmic_rev[3]= pmic_data[n].pmic_version[3];
995 dt_entry_array[k].offset = (uint32_t)dtb;
996 dt_entry_array[k].size = dtb_size;
997 k++;
998 }
999
1000 } else {
1001 dt_entry_array[k].platform_id = platform_data[i].platform_id;
1002 dt_entry_array[k].soc_rev = platform_data[i].soc_rev;
1003 dt_entry_array[k].variant_id = board_data[j].variant_id;
1004 dt_entry_array[k].board_hw_subtype = board_data[j].platform_subtype;
1005 dt_entry_array[k].pmic_rev[0]= board_pmic_target(0);
1006 dt_entry_array[k].pmic_rev[1]= board_pmic_target(1);
1007 dt_entry_array[k].pmic_rev[2]= board_pmic_target(2);
1008 dt_entry_array[k].pmic_rev[3]= board_pmic_target(3);
1009 dt_entry_array[k].offset = (uint32_t)dtb;
1010 dt_entry_array[k].size = dtb_size;
vijay kumar89d36d82014-06-30 19:32:18 +05301011 k++;
1012 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -07001013 }
Lijuan Gao9f152862014-08-18 13:45:24 +08001014 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -07001015
Lijuan Gao9f152862014-08-18 13:45:24 +08001016 for (i=0 ;i < num_entries; i++) {
1017 dprintf(SPEW, "Found an appended flattened device tree (%s - %u %u %u 0x%x)\n",
1018 *model ? model : "unknown",
1019 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 +05301020
Lijuan Gao9f152862014-08-18 13:45:24 +08001021 if (platform_dt_absolute_match(&(dt_entry_array[i]), dtb_list)) {
1022 dprintf(SPEW, "Device tree exact match the board: <%u %u %u 0x%x> == <%u %u %u 0x%x>\n",
1023 dt_entry_array[i].platform_id,
1024 dt_entry_array[i].variant_id,
1025 dt_entry_array[i].soc_rev,
1026 dt_entry_array[i].board_hw_subtype,
1027 board_platform_id(),
1028 board_hardware_id(),
1029 board_hardware_subtype(),
1030 board_soc_version());
vijay kumar89d36d82014-06-30 19:32:18 +05301031
Lijuan Gao9f152862014-08-18 13:45:24 +08001032 } else {
1033 dprintf(SPEW, "Device tree's msm_id doesn't match the board: <%u %u %u 0x%x> != <%u %u %u 0x%x>\n",
1034 dt_entry_array[i].platform_id,
1035 dt_entry_array[i].variant_id,
1036 dt_entry_array[i].soc_rev,
1037 dt_entry_array[i].board_hw_subtype,
1038 board_platform_id(),
1039 board_hardware_id(),
1040 board_hardware_subtype(),
1041 board_soc_version());
Channagoud Kadabia4dbe332013-09-05 17:44:11 -07001042 }
1043 }
Lijuan Gao9f152862014-08-18 13:45:24 +08001044
1045 free(board_data);
1046 free(platform_data);
1047 if (pmic_data)
1048 free(pmic_data);
1049 free(dt_entry_array);
Dima Zavinc46f8382013-05-03 12:23:06 -07001050 }
Lijuan Gao9f152862014-08-18 13:45:24 +08001051 if (model)
vijay kumar89d36d82014-06-30 19:32:18 +05301052 free(model);
Lijuan Gao9f152862014-08-18 13:45:24 +08001053 return true;
Dima Zavinc46f8382013-05-03 12:23:06 -07001054}
1055
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301056/* function to handle the overlay in independent thread */
1057static int dtb_overlay_handler(void *args)
1058{
1059 dprintf(SPEW, "thread %s() started\n", __func__);
1060
1061 soc_dtb_hdr = ufdt_install_blob(soc_dtb, fdt_totalsize(soc_dtb));
1062 if(!soc_dtb_hdr)
1063 {
1064 dprintf(CRITICAL, "ERROR: Install Blob failed\n");
1065 ret = DTBO_ERROR;
1066 goto out;
1067 }
1068 final_dtb_hdr = ufdt_apply_overlay(soc_dtb_hdr, fdt_totalsize(soc_dtb_hdr),board_dtb,
1069 fdt_totalsize(board_dtb));
1070 if (!final_dtb_hdr)
1071 {
1072 dprintf(CRITICAL, "ERROR: UFDT apply overlay failed\n");
1073 ret = DTBO_ERROR;
1074 goto out;
1075 }
1076out:
1077 /* This flag can only be updated here, hence it is not protected */
1078 event_signal(&dtbo_event, true);
1079 thread_exit(0);
1080 return 0;
1081}
1082
1083/*
1084 * Function to check and form new dtb with Overlay support.
1085*/
1086dtbo_error dev_tree_appended_with_dtbo(void *kernel, uint32_t kernel_size,
1087 uint32_t dtb_offset, void *tags)
1088{
1089 void *dtbo_image_buf = NULL;
Mayank Groverb61c0c22018-09-04 15:09:32 +05301090 uint32_t dtbo_image_sz = 0;
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301091
Mayank Grover302432a2017-12-08 17:18:58 +05301092 bs_set_timestamp(BS_DTB_OVERLAY_START);
Mayank Groverb61c0c22018-09-04 15:09:32 +05301093 ret = load_validate_dtbo_image(&dtbo_image_buf, &dtbo_image_sz);
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301094 if (ret == DTBO_SUCCESS)
1095 {
1096 final_dtb_hdr = soc_dtb = get_soc_dtb(kernel,
1097 kernel_size, dtb_offset);
1098 if(!soc_dtb)
1099 {
1100 ret = DTBO_ERROR;
1101 goto out;
1102 }
1103
1104 if (dtbo_needed)
1105 {
1106 board_dtb = get_board_dtb(dtbo_image_buf);
1107 if(!board_dtb)
1108 {
1109 ret = DTBO_ERROR;
1110 goto out;
1111 }
1112
1113 if((ADD_OF((fdt_totalsize(soc_dtb)), (fdt_totalsize(board_dtb)))) > MAX_DTBO_SZ)
1114 {
1115 dprintf(CRITICAL, "ERROR: dtb greater than max supported.\n");
1116 ret = DTBO_ERROR;
1117 goto out;
1118 }
1119
1120 /*
1121 spawn a seperate thread for dtbo overlay with indpendent,
1122 stack to avoid issues with stack corruption seen during flattening,
1123 of dtb in overlay functionality
1124 */
1125 {
1126 thread_t *thr = NULL;
1127 event_init(&dtbo_event, 0, EVENT_FLAG_AUTOUNSIGNAL);
1128 thr = thread_create("dtb_overlay", dtb_overlay_handler, 0,
1129 DEFAULT_PRIORITY, DTBO_STACK_SIZE);
1130 if (!thr)
1131 {
1132 dprintf(CRITICAL, "ERROR: Failed to create DTBO thread.\n");
1133 ret = DTBO_ERROR;
1134 goto out;
1135 }
1136 thread_resume(thr);
1137
1138 /* block current thread, untill woken up by dtb_overlay_handler. */
1139 event_wait(&dtbo_event);
1140
1141 /* ret is updated by dtb overlay thread, in case of error */
1142 if(ret == DTBO_ERROR)
1143 {
1144 goto out;
1145 }
1146 } /* dtbo_overlay_handler exited */
1147
1148 }
1149 memscpy(tags, fdt_totalsize(final_dtb_hdr), final_dtb_hdr,
1150 fdt_totalsize(final_dtb_hdr));
Mayank Grover71f63862018-05-03 17:06:41 +05301151 dprintf(INFO, "DTB overlay is successful\n");
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301152 }
1153 else
1154 {
Mayank Grover71f63862018-05-03 17:06:41 +05301155 dprintf(INFO, "ERROR: DTBO read is not valid\n DTB Overlay failed.\n");
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301156 ret = DTBO_NOT_SUPPORTED;
1157 }
1158out:
Mayank Grover302432a2017-12-08 17:18:58 +05301159 bs_set_timestamp(BS_DTB_OVERLAY_END);
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301160 return ret;
1161}
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001162/*
Dima Zavin77e41f32013-03-06 16:10:43 -08001163 * Will relocate the DTB to the tags addr if the device tree is found and return
1164 * its address
1165 *
Parth Dixit30e1a762019-07-08 21:37:33 +05301166 * Arguments: kernel - Start address of the kernel/bootimage loaded in RAM
Dima Zavin77e41f32013-03-06 16:10:43 -08001167 * tags - Start address of the tags loaded in RAM
Parth Dixit30e1a762019-07-08 21:37:33 +05301168 * kernel_size - Size of the kernel/bootimage size in bytes
Channagoud Kadabi704cd562013-04-25 15:19:59 -07001169 *
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001170 * Return Value: DTB address : If appended device tree is found
Dima Zavin77e41f32013-03-06 16:10:43 -08001171 * 'NULL' : Otherwise
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001172 */
Matthew Qinbb7923d2015-02-09 10:56:09 +08001173void *dev_tree_appended(void *kernel, uint32_t kernel_size, uint32_t dtb_offset, void *tags)
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001174{
Parth Dixit97e47bb2016-03-07 17:20:44 +05301175 uintptr_t kernel_end = (uintptr_t)kernel + kernel_size;
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001176 uint32_t app_dtb_offset = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +08001177 void *dtb = NULL;
Shashank Mittalc0f10282013-07-15 14:53:31 -07001178 void *bestmatch_tag = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +08001179 struct dt_entry *best_match_dt_entry = NULL;
Shashank Mittalc0f10282013-07-15 14:53:31 -07001180 uint32_t bestmatch_tag_size;
Lijuan Gao9f152862014-08-18 13:45:24 +08001181 struct dt_entry_node *dt_entry_queue = NULL;
1182 struct dt_entry_node *dt_node_tmp1 = NULL;
1183 struct dt_entry_node *dt_node_tmp2 = NULL;
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301184 dtbo_error ret = DTBO_NOT_SUPPORTED;
1185
lijuangdc1b5422018-05-07 17:12:59 +08001186 if (dtb_offset)
1187 app_dtb_offset = dtb_offset;
1188 else
1189 memcpy((void*) &app_dtb_offset, (void*) (kernel + DTB_OFFSET), sizeof(uint32_t));
1190
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301191 /* Check for dtbo support */
lijuangdc1b5422018-05-07 17:12:59 +08001192 ret = dev_tree_appended_with_dtbo(kernel, kernel_size, app_dtb_offset, tags);
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301193 if (ret == DTBO_SUCCESS)
1194 return tags;
1195 else if (ret == DTBO_ERROR)
1196 return NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +08001197
Lijuan Gao9f152862014-08-18 13:45:24 +08001198 /* Initialize the dtb entry node*/
1199 dt_entry_queue = (struct dt_entry_node *)
1200 malloc(sizeof(struct dt_entry_node));
1201
1202 if (!dt_entry_queue) {
1203 dprintf(CRITICAL, "Out of memory\n");
1204 return NULL;
1205 }
1206 list_initialize(&dt_entry_queue->node);
1207
vijay kumare2a5ea82014-06-25 12:24:14 +05301208 if (((uintptr_t)kernel + (uintptr_t)app_dtb_offset) < (uintptr_t)kernel) {
1209 return NULL;
1210 }
Parth Dixit97e47bb2016-03-07 17:20:44 +05301211 dtb = (void *)((uintptr_t)kernel + app_dtb_offset);
1212
vijay kumare2a5ea82014-06-25 12:24:14 +05301213 while (((uintptr_t)dtb + sizeof(struct fdt_header)) < (uintptr_t)kernel_end) {
Dima Zavinc46f8382013-05-03 12:23:06 -07001214 struct fdt_header dtb_hdr;
1215 uint32_t dtb_size;
Dima Zavin77e41f32013-03-06 16:10:43 -08001216
Dima Zavinc46f8382013-05-03 12:23:06 -07001217 /* the DTB could be unaligned, so extract the header,
1218 * and operate on it separately */
1219 memcpy(&dtb_hdr, dtb, sizeof(struct fdt_header));
1220 if (fdt_check_header((const void *)&dtb_hdr) != 0 ||
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +05301221 fdt_check_header_ext((const void *)&dtb_hdr) != 0 ||
vijay kumare2a5ea82014-06-25 12:24:14 +05301222 ((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) < (uintptr_t)dtb) ||
1223 ((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) > (uintptr_t)kernel_end))
Dima Zavinc46f8382013-05-03 12:23:06 -07001224 break;
1225 dtb_size = fdt_totalsize(&dtb_hdr);
1226
Lijuan Gao9f152862014-08-18 13:45:24 +08001227 dev_tree_compatible(dtb, dtb_size, dt_entry_queue);
Dima Zavinc46f8382013-05-03 12:23:06 -07001228
1229 /* goto the next device tree if any */
1230 dtb += dtb_size;
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001231 }
Dima Zavinc46f8382013-05-03 12:23:06 -07001232
Lijuan Gao9f152862014-08-18 13:45:24 +08001233 best_match_dt_entry = platform_dt_match_best(dt_entry_queue);
1234 if (best_match_dt_entry){
1235 bestmatch_tag = (void *)best_match_dt_entry->offset;
1236 bestmatch_tag_size = best_match_dt_entry->size;
Parth Dixit30e1a762019-07-08 21:37:33 +05301237 dtb_idx = best_match_dt_entry->idx;
1238 dprintf(INFO, "Best match DTB tags %u/%u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1239 best_match_dt_entry->idx, best_match_dt_entry->platform_id,
1240 best_match_dt_entry->variant_id, best_match_dt_entry->board_hw_subtype,
1241 best_match_dt_entry->soc_rev, best_match_dt_entry->pmic_rev[0],
1242 best_match_dt_entry->pmic_rev[1], best_match_dt_entry->pmic_rev[2],
1243 best_match_dt_entry->pmic_rev[3], best_match_dt_entry->offset,
1244 best_match_dt_entry->size);
Lijuan Gao9f152862014-08-18 13:45:24 +08001245 dprintf(INFO, "Using pmic info 0x%0x/0x%x/0x%x/0x%0x for device 0x%0x/0x%x/0x%x/0x%0x\n",
1246 best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],
1247 best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],
1248 board_pmic_target(0), board_pmic_target(1),
1249 board_pmic_target(2), board_pmic_target(3));
1250 }
1251 /* free queue's memory */
1252 list_for_every_entry(&dt_entry_queue->node, dt_node_tmp1, dt_node, node) {
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001253 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001254 dt_entry_list_delete(dt_node_tmp1);
1255 dt_node_tmp1 = dt_node_tmp2;
1256 }
1257
Shashank Mittalc0f10282013-07-15 14:53:31 -07001258 if(bestmatch_tag) {
Parth Dixitc2f0cb92016-03-10 10:40:14 +05301259 if (check_aboot_addr_range_overlap((uintptr_t)tags, bestmatch_tag_size)) {
1260 dprintf(CRITICAL, "Tags addresses overlap with aboot addresses.\n");
1261 return NULL;
1262 }
Shashank Mittalc0f10282013-07-15 14:53:31 -07001263 memcpy(tags, bestmatch_tag, bestmatch_tag_size);
1264 /* clear out the old DTB magic so kernel doesn't find it */
1265 *((uint32_t *)(kernel + app_dtb_offset)) = 0;
1266 return tags;
1267 }
1268
Dima Zavinc46f8382013-05-03 12:23:06 -07001269 dprintf(CRITICAL, "DTB offset is incorrect, kernel image does not have appended DTB\n");
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001270
David Ng59c4a782015-05-14 15:51:44 -07001271 dprintf(INFO, "Device info 0x%08x/%08x/0x%08x/%u, pmic 0x%0x/0x%x/0x%x/0x%0x\n",
1272 board_platform_id(), board_soc_version(),
1273 board_target_id(), board_hardware_subtype(),
1274 board_pmic_target(0), board_pmic_target(1),
1275 board_pmic_target(2), board_pmic_target(3));
Dima Zavin77e41f32013-03-06 16:10:43 -08001276 return NULL;
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001277}
1278
Joel Kingaa335dc2013-06-03 16:11:08 -07001279/* Returns 0 if the device tree is valid. */
Deepa Dinamani87252952013-09-09 13:58:27 -07001280int dev_tree_validate(struct dt_table *table, unsigned int page_size, uint32_t *dt_hdr_size)
Joel Kingaa335dc2013-06-03 16:11:08 -07001281{
1282 int dt_entry_size;
Channagoud Kadabid87c2772014-06-20 15:41:55 -07001283 uint64_t hdr_size;
Joel Kingaa335dc2013-06-03 16:11:08 -07001284
1285 /* Validate the device tree table header */
1286 if(table->magic != DEV_TREE_MAGIC) {
1287 dprintf(CRITICAL, "ERROR: Bad magic in device tree table \n");
1288 return -1;
1289 }
1290
1291 if (table->version == DEV_TREE_VERSION_V1) {
1292 dt_entry_size = sizeof(struct dt_entry_v1);
1293 } else if (table->version == DEV_TREE_VERSION_V2) {
Lijuan Gao9f152862014-08-18 13:45:24 +08001294 dt_entry_size = sizeof(struct dt_entry_v2);
1295 } else if (table->version == DEV_TREE_VERSION_V3) {
Joel Kingaa335dc2013-06-03 16:11:08 -07001296 dt_entry_size = sizeof(struct dt_entry);
1297 } else {
1298 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
1299 table->version);
1300 return -1;
1301 }
1302
Channagoud Kadabid87c2772014-06-20 15:41:55 -07001303 hdr_size = (uint64_t)table->num_entries * dt_entry_size + DEV_TREE_HEADER_SIZE;
1304
Deepa Dinamani87252952013-09-09 13:58:27 -07001305 /* Roundup to page_size. */
1306 hdr_size = ROUNDUP(hdr_size, page_size);
1307
Channagoud Kadabid87c2772014-06-20 15:41:55 -07001308 if (hdr_size > UINT_MAX)
1309 return -1;
1310 else
1311 *dt_hdr_size = hdr_size & UINT_MAX;
Joel Kingaa335dc2013-06-03 16:11:08 -07001312
1313 return 0;
1314}
1315
Lijuan Gao9f152862014-08-18 13:45:24 +08001316static int platform_dt_absolute_match(struct dt_entry *cur_dt_entry, struct dt_entry_node *dt_list)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001317{
Lijuan Gaof8e95722014-12-23 03:03:12 -05001318 uint32_t cur_dt_hlos_ddr;
Lijuan Gao9f152862014-08-18 13:45:24 +08001319 uint32_t cur_dt_hw_platform;
1320 uint32_t cur_dt_hw_subtype;
1321 uint32_t cur_dt_msm_id;
1322 dt_node *dt_node_tmp = NULL;
Channagoud Kadabi571193a2014-02-05 13:58:49 -08001323
Lijuan Gao9f152862014-08-18 13:45:24 +08001324 /* Platform-id
1325 * bit no |31 24|23 16|15 0|
1326 * |reserved|foundry-id|msm-id|
1327 */
1328 cur_dt_msm_id = (cur_dt_entry->platform_id & 0x0000ffff);
1329 cur_dt_hw_platform = (cur_dt_entry->variant_id & 0x000000ff);
Lijuan Gao0621b862014-09-02 10:02:52 +08001330 cur_dt_hw_subtype = (cur_dt_entry->board_hw_subtype & 0xff);
Lijuan Gao9f152862014-08-18 13:45:24 +08001331
Lijuan Gaof8e95722014-12-23 03:03:12 -05001332 /* Determine the bits 10:8 to check the DT with the DDR Size */
1333 cur_dt_hlos_ddr = (cur_dt_entry->board_hw_subtype & 0x700);
Channagoud Kadabi571193a2014-02-05 13:58:49 -08001334
Lijuan Gao9f152862014-08-18 13:45:24 +08001335 /* 1. must match the msm_id, platform_hw_id, platform_subtype and DDR size
1336 * soc, board major/minor, pmic major/minor must less than board info
1337 * 2. find the matched DTB then return 1
1338 * 3. otherwise return 0
Maria Yu2e2d2c22013-07-03 19:20:33 +08001339 */
Lijuan Gao9f152862014-08-18 13:45:24 +08001340 if((cur_dt_msm_id == (board_platform_id() & 0x0000ffff)) &&
1341 (cur_dt_hw_platform == board_hardware_id()) &&
1342 (cur_dt_hw_subtype == board_hardware_subtype()) &&
Lijuan Gaof8e95722014-12-23 03:03:12 -05001343 (cur_dt_hlos_ddr == (target_get_hlos_subtype() & 0x700)) &&
Lijuan Gao9f152862014-08-18 13:45:24 +08001344 (cur_dt_entry->soc_rev <= board_soc_version()) &&
1345 ((cur_dt_entry->variant_id & 0x00ffff00) <= (board_target_id() & 0x00ffff00)) &&
1346 ((cur_dt_entry->pmic_rev[0] & 0x00ffff00) <= (board_pmic_target(0) & 0x00ffff00)) &&
1347 ((cur_dt_entry->pmic_rev[1] & 0x00ffff00) <= (board_pmic_target(1) & 0x00ffff00)) &&
1348 ((cur_dt_entry->pmic_rev[2] & 0x00ffff00) <= (board_pmic_target(2) & 0x00ffff00)) &&
1349 ((cur_dt_entry->pmic_rev[3] & 0x00ffff00) <= (board_pmic_target(3) & 0x00ffff00))) {
Maria Yu2e2d2c22013-07-03 19:20:33 +08001350
Lijuan Gao9f152862014-08-18 13:45:24 +08001351 dt_node_tmp = dt_entry_list_init();
1352 memcpy((char*)dt_node_tmp->dt_entry_m,(char*)cur_dt_entry, sizeof(struct dt_entry));
1353
1354 dprintf(SPEW, "Add DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1355 dt_node_tmp->dt_entry_m->platform_id, dt_node_tmp->dt_entry_m->variant_id,
1356 dt_node_tmp->dt_entry_m->board_hw_subtype, dt_node_tmp->dt_entry_m->soc_rev,
1357 dt_node_tmp->dt_entry_m->pmic_rev[0], dt_node_tmp->dt_entry_m->pmic_rev[1],
1358 dt_node_tmp->dt_entry_m->pmic_rev[2], dt_node_tmp->dt_entry_m->pmic_rev[3],
1359 dt_node_tmp->dt_entry_m->offset, dt_node_tmp->dt_entry_m->size);
1360
1361 insert_dt_entry_in_queue(dt_list, dt_node_tmp);
1362 return 1;
1363 }
1364 return 0;
1365}
1366
1367static int platform_dt_absolute_compat_match(struct dt_entry_node *dt_list, uint32_t dtb_info) {
1368 struct dt_entry_node *dt_node_tmp1 = NULL;
1369 struct dt_entry_node *dt_node_tmp2 = NULL;
1370 uint32_t current_info = 0;
1371 uint32_t board_info = 0;
1372 uint32_t best_info = 0;
1373 uint32_t current_pmic_model[4] = {0, 0, 0, 0};
1374 uint32_t board_pmic_model[4] = {0, 0, 0, 0};
1375 uint32_t best_pmic_model[4] = {0, 0, 0, 0};
1376 uint32_t delete_current_dt = 0;
1377 uint32_t i;
1378
1379 /* start to select the exact entry
1380 * default to exact match 0, if find current DTB entry info is the same as board info,
1381 * then exact match board info.
1382 */
1383 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1384 if (!dt_node_tmp1){
1385 dprintf(SPEW, "Current node is the end\n");
1386 break;
1387 }
1388 switch(dtb_info) {
1389 case DTB_FOUNDRY:
1390 current_info = ((dt_node_tmp1->dt_entry_m->platform_id) & 0x00ff0000);
Channagoud Kadabi4cffc272014-10-29 11:23:26 -07001391 board_info = board_foundry_id() << 16;
Lijuan Gao9f152862014-08-18 13:45:24 +08001392 break;
1393 case DTB_PMIC_MODEL:
1394 for (i = 0; i < 4; i++) {
1395 current_pmic_model[i] = (dt_node_tmp1->dt_entry_m->pmic_rev[i] & 0xff);
1396 board_pmic_model[i] = (board_pmic_target(i) & 0xff);
1397 }
1398 break;
Lijuan Gaof8e95722014-12-23 03:03:12 -05001399 case DTB_PANEL_TYPE:
1400 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0x1800);
1401 board_info = (target_get_hlos_subtype() & 0x1800);
1402 break;
1403 case DTB_BOOT_DEVICE:
1404 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0xf0000);
1405 board_info = (target_get_hlos_subtype() & 0xf0000);
1406 break;
Lijuan Gao9f152862014-08-18 13:45:24 +08001407 default:
1408 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
1409 dtb_info);
Maria Yuca51ee22013-06-27 21:45:24 +08001410 return 0;
Lijuan Gao9f152862014-08-18 13:45:24 +08001411 }
1412
1413 if (dtb_info == DTB_PMIC_MODEL) {
1414 if ((current_pmic_model[0] == board_pmic_model[0]) &&
1415 (current_pmic_model[1] == board_pmic_model[1]) &&
1416 (current_pmic_model[2] == board_pmic_model[2]) &&
1417 (current_pmic_model[3] == board_pmic_model[3])) {
1418
1419 for (i = 0; i < 4; i++) {
1420 best_pmic_model[i] = current_pmic_model[i];
1421 }
1422 break;
1423 }
1424 } else {
1425 if (current_info == board_info) {
1426 best_info = current_info;
1427 break;
1428 }
1429 }
1430 }
1431
1432 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1433 if (!dt_node_tmp1){
1434 dprintf(SPEW, "Current node is the end\n");
1435 break;
1436 }
1437 switch(dtb_info) {
1438 case DTB_FOUNDRY:
1439 current_info = ((dt_node_tmp1->dt_entry_m->platform_id) & 0x00ff0000);
1440 break;
1441 case DTB_PMIC_MODEL:
1442 for (i = 0; i < 4; i++) {
1443 current_pmic_model[i] = (dt_node_tmp1->dt_entry_m->pmic_rev[i] & 0xff);
1444 }
1445 break;
Lijuan Gaof8e95722014-12-23 03:03:12 -05001446 case DTB_PANEL_TYPE:
1447 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0x1800);
1448 break;
1449 case DTB_BOOT_DEVICE:
1450 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0xf0000);
1451 break;
Lijuan Gao9f152862014-08-18 13:45:24 +08001452 default:
1453 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
1454 dtb_info);
1455 return 0;
1456 }
1457
1458 if (dtb_info == DTB_PMIC_MODEL) {
1459 if ((current_pmic_model[0] != best_pmic_model[0]) ||
1460 (current_pmic_model[1] != best_pmic_model[1]) ||
1461 (current_pmic_model[2] != best_pmic_model[2]) ||
1462 (current_pmic_model[3] != best_pmic_model[3])) {
1463
1464 delete_current_dt = 1;
1465 }
1466 } else {
1467 if (current_info != best_info) {
1468 delete_current_dt = 1;
1469 }
1470 }
1471
1472 if (delete_current_dt) {
1473 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1474 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
1475 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
1476 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
1477 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
1478 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
1479
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001480 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001481 dt_entry_list_delete(dt_node_tmp1);
1482 dt_node_tmp1 = dt_node_tmp2;
1483 delete_current_dt = 0;
Maria Yuca51ee22013-06-27 21:45:24 +08001484 }
1485 }
Maria Yuca51ee22013-06-27 21:45:24 +08001486
Maria Yu2e2d2c22013-07-03 19:20:33 +08001487 return 1;
Maria Yuca51ee22013-06-27 21:45:24 +08001488}
1489
Lijuan Gao9f152862014-08-18 13:45:24 +08001490static int update_dtb_entry_node(struct dt_entry_node *dt_list, uint32_t dtb_info) {
1491 struct dt_entry_node *dt_node_tmp1 = NULL;
1492 struct dt_entry_node *dt_node_tmp2 = NULL;
1493 uint32_t current_info = 0;
1494 uint32_t board_info = 0;
1495 uint32_t best_info = 0;
1496
1497 /* start to select the best entry*/
1498 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1499 if (!dt_node_tmp1){
1500 dprintf(SPEW, "Current node is the end\n");
1501 break;
1502 }
1503 switch(dtb_info) {
1504 case DTB_SOC:
1505 current_info = dt_node_tmp1->dt_entry_m->soc_rev;
1506 board_info = board_soc_version();
1507 break;
1508 case DTB_MAJOR_MINOR:
1509 current_info = ((dt_node_tmp1->dt_entry_m->variant_id) & 0x00ffff00);
1510 board_info = (board_target_id() & 0x00ffff00);
1511 break;
1512 case DTB_PMIC0:
1513 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[0]) & 0x00ffff00);
1514 board_info = (board_pmic_target(0) & 0x00ffff00);
1515 break;
1516 case DTB_PMIC1:
1517 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[1]) & 0x00ffff00);
1518 board_info = (board_pmic_target(1) & 0x00ffff00);
1519 break;
1520 case DTB_PMIC2:
1521 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[2]) & 0x00ffff00);
1522 board_info = (board_pmic_target(2) & 0x00ffff00);
1523 break;
1524 case DTB_PMIC3:
1525 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[3]) & 0x00ffff00);
1526 board_info = (board_pmic_target(3) & 0x00ffff00);
1527 break;
1528 default:
1529 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
1530 dtb_info);
1531 return 0;
1532 }
1533
1534 if (current_info == board_info) {
1535 best_info = current_info;
1536 break;
1537 }
1538 if ((current_info < board_info) && (current_info > best_info)) {
1539 best_info = current_info;
1540 }
1541 if (current_info < best_info) {
1542 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1543 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
1544 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
1545 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
1546 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
1547 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
1548
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001549 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001550 dt_entry_list_delete(dt_node_tmp1);
1551 dt_node_tmp1 = dt_node_tmp2;
1552 }
1553 }
1554
1555 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1556 if (!dt_node_tmp1){
1557 dprintf(SPEW, "Current node is the end\n");
1558 break;
1559 }
1560 switch(dtb_info) {
1561 case DTB_SOC:
1562 current_info = dt_node_tmp1->dt_entry_m->soc_rev;
1563 break;
1564 case DTB_MAJOR_MINOR:
1565 current_info = ((dt_node_tmp1->dt_entry_m->variant_id) & 0x00ffff00);
1566 break;
1567 case DTB_PMIC0:
1568 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[0]) & 0x00ffff00);
1569 break;
1570 case DTB_PMIC1:
1571 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[1]) & 0x00ffff00);
1572 break;
1573 case DTB_PMIC2:
1574 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[2]) & 0x00ffff00);
1575 break;
1576 case DTB_PMIC3:
1577 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[3]) & 0x00ffff00);
1578 break;
1579 default:
1580 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
1581 dtb_info);
1582 return 0;
1583 }
1584
1585 if (current_info != best_info) {
1586 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1587 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
1588 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
1589 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
1590 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
1591 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
1592
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001593 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001594 dt_entry_list_delete(dt_node_tmp1);
1595 dt_node_tmp1 = dt_node_tmp2;
1596 }
1597 }
1598 return 1;
1599}
1600
1601static struct dt_entry *platform_dt_match_best(struct dt_entry_node *dt_list)
1602{
1603 struct dt_entry_node *dt_node_tmp1 = NULL;
1604
1605 /* check Foundry id
1606 * the foundry id must exact match board founddry id, this is compatibility check,
1607 * if couldn't find the exact match from DTB, will exact match 0x0.
1608 */
1609 if (!platform_dt_absolute_compat_match(dt_list, DTB_FOUNDRY))
1610 return NULL;
1611
1612 /* check PMIC model
1613 * the PMIC model must exact match board PMIC model, this is compatibility check,
1614 * if couldn't find the exact match from DTB, will exact match 0x0.
1615 */
1616 if (!platform_dt_absolute_compat_match(dt_list, DTB_PMIC_MODEL))
1617 return NULL;
1618
Lijuan Gaof8e95722014-12-23 03:03:12 -05001619 /* check panel type
1620 * the panel type must exact match board panel type, this is compatibility check,
1621 * if couldn't find the exact match from DTB, will exact match 0x0.
1622 */
1623 if (!platform_dt_absolute_compat_match(dt_list, DTB_PANEL_TYPE))
1624 return NULL;
1625
1626 /* check boot device subtype
1627 * the boot device subtype must exact match board boot device subtype, this is compatibility check,
1628 * if couldn't find the exact match from DTB, will exact match 0x0.
1629 */
1630 if (!platform_dt_absolute_compat_match(dt_list, DTB_BOOT_DEVICE))
1631 return NULL;
1632
Lijuan Gao9f152862014-08-18 13:45:24 +08001633 /* check soc version
1634 * the suitable soc version must less than or equal to board soc version
1635 */
1636 if (!update_dtb_entry_node(dt_list, DTB_SOC))
1637 return NULL;
1638
1639 /*check major and minor version
1640 * the suitable major&minor version must less than or equal to board major&minor version
1641 */
1642 if (!update_dtb_entry_node(dt_list, DTB_MAJOR_MINOR))
1643 return NULL;
1644
1645 /*check pmic info
1646 * the suitable pmic major&minor info must less than or equal to board pmic major&minor version
1647 */
1648 if (!update_dtb_entry_node(dt_list, DTB_PMIC0))
1649 return NULL;
1650 if (!update_dtb_entry_node(dt_list, DTB_PMIC1))
1651 return NULL;
1652 if (!update_dtb_entry_node(dt_list, DTB_PMIC2))
1653 return NULL;
1654 if (!update_dtb_entry_node(dt_list, DTB_PMIC3))
1655 return NULL;
1656
1657 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1658 if (!dt_node_tmp1) {
1659 dprintf(CRITICAL, "ERROR: Couldn't find the suitable DTB!\n");
1660 return NULL;
1661 }
1662 if (dt_node_tmp1->dt_entry_m)
1663 return dt_node_tmp1->dt_entry_m;
1664 }
1665
1666 return NULL;
1667}
1668
1669/* Function to obtain the index information for the correct device tree
1670 * based on the platform data.
1671 * If a matching device tree is found, the information is returned in the
1672 * "dt_entry_info" out parameter and a function value of 0 is returned, otherwise
1673 * a non-zero function value is returned.
1674 */
1675int dev_tree_get_entry_info(struct dt_table *table, struct dt_entry *dt_entry_info)
Maria Yuca51ee22013-06-27 21:45:24 +08001676{
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001677 uint32_t i;
Lijuan Gao9f152862014-08-18 13:45:24 +08001678 unsigned char *table_ptr = NULL;
Joel Kingaa335dc2013-06-03 16:11:08 -07001679 struct dt_entry dt_entry_buf_1;
Lijuan Gao9f152862014-08-18 13:45:24 +08001680 struct dt_entry *cur_dt_entry = NULL;
1681 struct dt_entry *best_match_dt_entry = NULL;
1682 struct dt_entry_v1 *dt_entry_v1 = NULL;
1683 struct dt_entry_v2 *dt_entry_v2 = NULL;
1684 struct dt_entry_node *dt_entry_queue = NULL;
1685 struct dt_entry_node *dt_node_tmp1 = NULL;
1686 struct dt_entry_node *dt_node_tmp2 = NULL;
Maria Yu2e2d2c22013-07-03 19:20:33 +08001687 uint32_t found = 0;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001688
Joel Kingaa335dc2013-06-03 16:11:08 -07001689 if (!dt_entry_info) {
1690 dprintf(CRITICAL, "ERROR: Bad parameter passed to %s \n",
1691 __func__);
1692 return -1;
1693 }
1694
1695 table_ptr = (unsigned char *)table + DEV_TREE_HEADER_SIZE;
1696 cur_dt_entry = &dt_entry_buf_1;
1697 best_match_dt_entry = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +08001698 dt_entry_queue = (struct dt_entry_node *)
1699 malloc(sizeof(struct dt_entry_node));
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001700
Lijuan Gao9f152862014-08-18 13:45:24 +08001701 if (!dt_entry_queue) {
1702 dprintf(CRITICAL, "Out of memory\n");
1703 return -1;
1704 }
1705
1706 list_initialize(&dt_entry_queue->node);
1707 dprintf(INFO, "DTB Total entry: %d, DTB version: %d\n", table->num_entries, table->version);
Maria Yu2e2d2c22013-07-03 19:20:33 +08001708 for(i = 0; found == 0 && i < table->num_entries; i++)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001709 {
Joel Kingaa335dc2013-06-03 16:11:08 -07001710 memset(cur_dt_entry, 0, sizeof(struct dt_entry));
1711 switch(table->version) {
1712 case DEV_TREE_VERSION_V1:
1713 dt_entry_v1 = (struct dt_entry_v1 *)table_ptr;
1714 cur_dt_entry->platform_id = dt_entry_v1->platform_id;
1715 cur_dt_entry->variant_id = dt_entry_v1->variant_id;
1716 cur_dt_entry->soc_rev = dt_entry_v1->soc_rev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001717 cur_dt_entry->board_hw_subtype = (dt_entry_v1->variant_id >> 0x18);
1718 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
1719 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
1720 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
1721 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
Joel Kingaa335dc2013-06-03 16:11:08 -07001722 cur_dt_entry->offset = dt_entry_v1->offset;
1723 cur_dt_entry->size = dt_entry_v1->size;
1724 table_ptr += sizeof(struct dt_entry_v1);
1725 break;
1726 case DEV_TREE_VERSION_V2:
Lijuan Gao9f152862014-08-18 13:45:24 +08001727 dt_entry_v2 = (struct dt_entry_v2*)table_ptr;
1728 cur_dt_entry->platform_id = dt_entry_v2->platform_id;
1729 cur_dt_entry->variant_id = dt_entry_v2->variant_id;
1730 cur_dt_entry->soc_rev = dt_entry_v2->soc_rev;
1731 /* For V2 version of DTBs we have platform version field as part
1732 * of variant ID, in such case the subtype will be mentioned as 0x0
1733 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
1734 * SS -- Subtype
1735 * PM -- Platform major version
1736 * Pm -- Platform minor version
1737 * PH -- Platform hardware CDP/MTP
1738 * In such case to make it compatible with LK algorithm move the subtype
1739 * from variant_id to subtype field
1740 */
1741 if (dt_entry_v2->board_hw_subtype == 0)
1742 cur_dt_entry->board_hw_subtype = (cur_dt_entry->variant_id >> 0x18);
1743 else
1744 cur_dt_entry->board_hw_subtype = dt_entry_v2->board_hw_subtype;
1745 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
1746 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
1747 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
1748 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
1749 cur_dt_entry->offset = dt_entry_v2->offset;
1750 cur_dt_entry->size = dt_entry_v2->size;
1751 table_ptr += sizeof(struct dt_entry_v2);
1752 break;
1753 case DEV_TREE_VERSION_V3:
Joel Kingaa335dc2013-06-03 16:11:08 -07001754 memcpy(cur_dt_entry, (struct dt_entry *)table_ptr,
1755 sizeof(struct dt_entry));
Lijuan Gao9f152862014-08-18 13:45:24 +08001756 /* For V3 version of DTBs we have platform version field as part
1757 * of variant ID, in such case the subtype will be mentioned as 0x0
1758 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
1759 * SS -- Subtype
1760 * PM -- Platform major version
1761 * Pm -- Platform minor version
1762 * PH -- Platform hardware CDP/MTP
1763 * In such case to make it compatible with LK algorithm move the subtype
1764 * from variant_id to subtype field
1765 */
1766 if (cur_dt_entry->board_hw_subtype == 0)
1767 cur_dt_entry->board_hw_subtype = (cur_dt_entry->variant_id >> 0x18);
1768
Joel Kingaa335dc2013-06-03 16:11:08 -07001769 table_ptr += sizeof(struct dt_entry);
1770 break;
1771 default:
1772 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
1773 table->version);
Lijuan Gao9f152862014-08-18 13:45:24 +08001774 free(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001775 return -1;
1776 }
1777
Lijuan Gao9f152862014-08-18 13:45:24 +08001778 /* DTBs must match the platform_id, platform_hw_id, platform_subtype and DDR size.
1779 * The satisfactory DTBs are stored in dt_entry_queue
1780 */
1781 platform_dt_absolute_match(cur_dt_entry, dt_entry_queue);
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -08001782
Lijuan Gao9f152862014-08-18 13:45:24 +08001783 }
1784 best_match_dt_entry = platform_dt_match_best(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001785 if (best_match_dt_entry) {
1786 *dt_entry_info = *best_match_dt_entry;
Maria Yu2e2d2c22013-07-03 19:20:33 +08001787 found = 1;
1788 }
1789
1790 if (found != 0) {
Sundarajan Srinivasan763c0db2014-05-20 17:08:36 -07001791 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 -07001792 dt_entry_info->platform_id, dt_entry_info->soc_rev,
1793 dt_entry_info->variant_id, dt_entry_info->board_hw_subtype,
Lijuan Gao9f152862014-08-18 13:45:24 +08001794 board_platform_id(), board_soc_version(),
1795 board_target_id(), board_hardware_subtype());
1796 if (dt_entry_info->pmic_rev[0] == 0 && dt_entry_info->pmic_rev[0] == 0 &&
1797 dt_entry_info->pmic_rev[0] == 0 && dt_entry_info->pmic_rev[0] == 0) {
1798 dprintf(SPEW, "No maintain pmic info in DTB, device pmic info is 0x%0x/0x%x/0x%x/0x%0x\n",
1799 board_pmic_target(0), board_pmic_target(1),
1800 board_pmic_target(2), board_pmic_target(3));
1801 } else {
1802 dprintf(INFO, "Using pmic info 0x%0x/0x%x/0x%x/0x%0x for device 0x%0x/0x%x/0x%x/0x%0x\n",
1803 dt_entry_info->pmic_rev[0], dt_entry_info->pmic_rev[1],
1804 dt_entry_info->pmic_rev[2], dt_entry_info->pmic_rev[3],
1805 board_pmic_target(0), board_pmic_target(1),
1806 board_pmic_target(2), board_pmic_target(3));
1807 }
Joel Kingaa335dc2013-06-03 16:11:08 -07001808 return 0;
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -08001809 }
1810
Lijuan Gao9f152862014-08-18 13:45:24 +08001811 dprintf(CRITICAL, "ERROR: Unable to find suitable device tree for device (%u/0x%08x/0x%08x/%u)\n",
1812 board_platform_id(), board_soc_version(),
1813 board_target_id(), board_hardware_subtype());
1814
1815 list_for_every_entry(&dt_entry_queue->node, dt_node_tmp1, dt_node, node) {
1816 /* free node memory */
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001817 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001818 dt_entry_list_delete(dt_node_tmp1);
1819 dt_node_tmp1 = dt_node_tmp2;
1820 }
1821 free(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001822 return -1;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001823}
1824
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001825/* Function to add the first RAM partition info to the device tree.
1826 * Note: The function replaces the reg property in the "/memory" node
1827 * with the addr and size provided.
1828 */
1829int dev_tree_add_first_mem_info(uint32_t *fdt, uint32_t offset, uint32_t addr, uint32_t size)
1830{
1831 int ret;
1832
1833 ret = fdt_setprop_u32(fdt, offset, "reg", addr);
1834
1835 if (ret)
1836 {
1837 dprintf(CRITICAL, "Failed to add the memory information addr: %d\n",
1838 ret);
1839 }
1840
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001841 ret = fdt_appendprop_u32(fdt, offset, "reg", size);
1842
1843 if (ret)
1844 {
1845 dprintf(CRITICAL, "Failed to add the memory information size: %d\n",
1846 ret);
1847 }
1848
1849 return ret;
1850}
1851
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001852static 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 -07001853{
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001854 int len;
1855 uint32_t *valp;
1856 int ret;
1857 uint32_t offset;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001858
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001859 mem_node->offset = mem_node_offset;
1860
1861 /* Get offset of the root node */
1862 ret = fdt_path_offset(fdt, "/");
1863 if (ret < 0)
1864 {
1865 dprintf(CRITICAL, "Could not find memory node.\n");
1866 return ret;
1867 }
1868
1869 offset = ret;
1870
1871 /* Find the #address-cells size. */
1872 valp = (uint32_t*)fdt_getprop(fdt, offset, "#address-cells", &len);
Lijuan Gaoae0927b2014-07-18 17:16:16 +08001873 if (len <= 0 || !valp)
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001874 {
1875 if (len == -FDT_ERR_NOTFOUND)
1876 {
1877 /* Property not found.
1878 * Assume standard sizes.
1879 */
1880 mem_node->addr_cell_size = 2;
1881 dprintf(CRITICAL, "Using default #addr_cell_size: %u\n", mem_node->addr_cell_size);
1882 }
1883 else
1884 {
1885 dprintf(CRITICAL, "Error finding the #address-cells property\n");
1886 return len;
1887 }
1888 }
1889 else
1890 mem_node->addr_cell_size = fdt32_to_cpu(*valp);
1891
1892 /* Find the #size-cells size. */
1893 valp = (uint32_t*)fdt_getprop(fdt, offset, "#size-cells", &len);
Lijuan Gaoae0927b2014-07-18 17:16:16 +08001894 if (len <= 0 || !valp)
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001895 {
1896 if (len == -FDT_ERR_NOTFOUND)
1897 {
1898 /* Property not found.
1899 * Assume standard sizes.
1900 */
1901 mem_node->size_cell_size = 1;
1902 dprintf(CRITICAL, "Using default #size_cell_size: %u\n", mem_node->size_cell_size);
1903 }
1904 else
1905 {
1906 dprintf(CRITICAL, "Error finding the #size-cells property\n");
1907 return len;
1908 }
1909 }
1910 else
1911 mem_node->size_cell_size = fdt32_to_cpu(*valp);
1912
1913 return 0;
1914}
1915
1916static void dev_tree_update_memory_node(uint32_t offset)
1917{
1918 mem_node.offset = offset;
1919 mem_node.addr_cell_size = 1;
1920 mem_node.size_cell_size = 1;
1921}
1922
1923/* Function to add the subsequent RAM partition info to the device tree. */
1924int dev_tree_add_mem_info(void *fdt, uint32_t offset, uint64_t addr, uint64_t size)
1925{
1926 int ret = 0;
1927
1928 if(smem_get_ram_ptable_version() >= 1)
1929 {
1930 ret = dev_tree_query_memory_cell_sizes(fdt, &mem_node, offset);
1931 if (ret < 0)
1932 {
1933 dprintf(CRITICAL, "Could not find #address-cells and #size-cells properties: ret %d\n", ret);
1934 return ret;
1935 }
1936
1937 }
1938 else
1939 {
1940 dev_tree_update_memory_node(offset);
1941 }
1942
1943 if (!(mem_node.mem_info_cnt))
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001944 {
1945 /* Replace any other reg prop in the memory node. */
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001946
1947 /* cell_size is the number of 32 bit words used to represent an address/length in the device tree.
1948 * memory node in DT can be either 32-bit(cell-size = 1) or 64-bit(cell-size = 2).So when updating
1949 * the memory node in the device tree, we write one word or two words based on cell_size = 1 or 2.
1950 */
1951
1952 if(mem_node.addr_cell_size == 2)
1953 {
1954 ret = fdt_setprop_u32(fdt, mem_node.offset, "reg", addr >> 32);
1955 if(ret)
1956 {
1957 dprintf(CRITICAL, "ERROR: Could not set prop reg for memory node\n");
1958 return ret;
1959 }
1960
1961 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1962 if(ret)
1963 {
1964 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1965 return ret;
1966 }
1967 }
1968 else
1969 {
1970 ret = fdt_setprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1971 if(ret)
1972 {
1973 dprintf(CRITICAL, "ERROR: Could not set prop reg for memory node\n");
1974 return ret;
1975 }
1976 }
1977
1978 mem_node.mem_info_cnt = 1;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001979 }
1980 else
1981 {
1982 /* Append the mem info to the reg prop for subsequent nodes. */
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001983 if(mem_node.addr_cell_size == 2)
1984 {
1985 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", addr >> 32);
1986 if(ret)
1987 {
1988 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1989 return ret;
1990 }
1991 }
1992
1993 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1994 if(ret)
1995 {
1996 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1997 return ret;
1998 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001999 }
2000
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07002001 if(mem_node.size_cell_size == 2)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002002 {
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07002003 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", size>>32);
2004 if(ret)
2005 {
2006 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
2007 return ret;
2008 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002009 }
2010
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07002011 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)size);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002012
2013 if (ret)
2014 {
2015 dprintf(CRITICAL, "Failed to add the memory information size: %d\n",
2016 ret);
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07002017 return ret;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002018 }
2019
2020 return ret;
2021}
2022
2023/* Top level function that updates the device tree. */
2024int update_device_tree(void *fdt, const char *cmdline,
2025 void *ramdisk, uint32_t ramdisk_size)
2026{
2027 int ret = 0;
2028 uint32_t offset;
lijuangc76a7632017-12-07 14:37:56 +08002029#if ENABLE_KASLRSEED_SUPPORT
lijuang0ac31232018-10-19 17:53:36 +08002030 uint64_t kaslrseed;
lijuangc76a7632017-12-07 14:37:56 +08002031#endif
Mayank Grover2533aab2018-02-23 18:06:07 +05302032 uint32_t cmdline_len = 0;
2033
2034 if (cmdline)
2035 cmdline_len = strlen(cmdline);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002036
2037 /* Check the device tree header */
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +05302038 ret = fdt_check_header(fdt) || fdt_check_header_ext(fdt);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002039 if (ret)
2040 {
2041 dprintf(CRITICAL, "Invalid device tree header \n");
2042 return ret;
2043 }
2044
P.V. Phani Kumar9cd95102016-03-09 12:35:23 +05302045 if (check_aboot_addr_range_overlap((uint32_t)fdt,
Mayank Grover2533aab2018-02-23 18:06:07 +05302046 (fdt_totalsize(fdt) + DTB_PAD_SIZE + cmdline_len))) {
P.V. Phani Kumar9cd95102016-03-09 12:35:23 +05302047 dprintf(CRITICAL, "Error: Fdt addresses overlap with aboot addresses.\n");
2048 return ret;
2049 }
2050
Deepa Dinamani1c970732013-04-19 14:23:01 -07002051 /* Add padding to make space for new nodes and properties. */
Mayank Grover2533aab2018-02-23 18:06:07 +05302052 ret = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + DTB_PAD_SIZE + cmdline_len);
Deepa Dinamani1c970732013-04-19 14:23:01 -07002053 if (ret!= 0)
2054 {
2055 dprintf(CRITICAL, "Failed to move/resize dtb buffer: %d\n", ret);
2056 return ret;
2057 }
2058
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002059 /* Get offset of the memory node */
2060 ret = fdt_path_offset(fdt, "/memory");
2061 if (ret < 0)
2062 {
2063 dprintf(CRITICAL, "Could not find memory node.\n");
2064 return ret;
2065 }
2066
2067 offset = ret;
2068
2069 ret = target_dev_tree_mem(fdt, offset);
2070 if(ret)
2071 {
2072 dprintf(CRITICAL, "ERROR: Cannot update memory node\n");
2073 return ret;
2074 }
2075
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002076 /* Get offset of the chosen node */
2077 ret = fdt_path_offset(fdt, "/chosen");
2078 if (ret < 0)
2079 {
2080 dprintf(CRITICAL, "Could not find chosen node.\n");
2081 return ret;
2082 }
2083
2084 offset = ret;
Maria Yuabde9542014-07-07 14:49:34 +08002085 if (cmdline)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002086 {
Maria Yuabde9542014-07-07 14:49:34 +08002087 /* Adding the cmdline to the chosen node */
2088 ret = fdt_appendprop_string(fdt, offset, (const char*)"bootargs", (const void*)cmdline);
2089 if (ret)
2090 {
2091 dprintf(CRITICAL, "ERROR: Cannot update chosen node [bootargs]\n");
2092 return ret;
2093 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002094 }
2095
lijuangc76a7632017-12-07 14:37:56 +08002096#if ENABLE_KASLRSEED_SUPPORT
lijuang0ac31232018-10-19 17:53:36 +08002097 if (!scm_random((uintptr_t *)&kaslrseed, sizeof(kaslrseed))) {
lijuangc76a7632017-12-07 14:37:56 +08002098 /* Adding Kaslr Seed to the chosen node */
2099 ret = fdt_appendprop_u64 (fdt, offset, (const char *)"kaslr-seed", (uint64_t)kaslrseed);
2100 if (ret)
2101 dprintf(CRITICAL, "ERROR: Cannot update chosen node [kaslr-seed] - 0x%x\n", ret);
2102 else
2103 dprintf(CRITICAL, "kaslr-Seed is added to chosen node\n");
2104 } else {
2105 dprintf(CRITICAL, "ERROR: Cannot generate Kaslr Seed\n");
2106 }
2107#endif
2108
Joonwoo Parka5b5f492014-02-13 18:24:48 -08002109 if (ramdisk_size) {
2110 /* Adding the initrd-start to the chosen node */
2111 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-start",
2112 (uint32_t)ramdisk);
2113 if (ret)
2114 {
2115 dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-start]\n");
2116 return ret;
2117 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002118
Joonwoo Parka5b5f492014-02-13 18:24:48 -08002119 /* Adding the initrd-end to the chosen node */
2120 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-end",
2121 ((uint32_t)ramdisk + ramdisk_size));
2122 if (ret)
2123 {
2124 dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-end]\n");
2125 return ret;
2126 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002127 }
2128
Mayank Grovera9ffe802019-06-03 14:08:40 +05302129#if ENABLE_BOOTDEVICE_MOUNT || DYNAMIC_PARTITION_SUPPORT
Kishor PK536904a2017-07-13 17:18:59 +05302130 /* Update fstab node */
2131 dprintf(SPEW, "Start of fstab node update:%zu ms\n", platform_get_sclk_count());
2132 if (update_fstab_node(fdt) != 0) {
2133 dprintf(CRITICAL, "ERROR: Cannot update fstab node\n");
2134 return ret;
2135 }
2136 dprintf(SPEW, "End of fstab node update:%zu ms\n", platform_get_sclk_count());
2137#endif
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002138 fdt_pack(fdt);
2139
Channagoud Kadabiffaea422014-12-05 15:45:41 -08002140#if ENABLE_PARTIAL_GOODS_SUPPORT
2141 update_partial_goods_dtb_nodes(fdt);
2142#endif
2143
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002144 return ret;
2145}
Kishor PK536904a2017-07-13 17:18:59 +05302146
Mayank Grovera9ffe802019-06-03 14:08:40 +05302147#if ENABLE_BOOTDEVICE_MOUNT || DYNAMIC_PARTITION_SUPPORT
Kishor PK536904a2017-07-13 17:18:59 +05302148/*Update device tree for fstab node */
2149static int update_fstab_node(void *fdt)
2150{
2151 int ret = 0;
2152 int str_len = 0;
2153 int parent_offset = 0;
2154 int subnode_offset = 0;
2155 int prop_length = 0;
2156 int prefix_string_len = 0;
2157 char *node_name = NULL;
2158 char *boot_dev_buf = NULL;
2159 char *new_str = NULL;
2160 char *prefix_str = NULL;
2161 char *suffix_str = NULL;
2162 const struct fdt_property *prop = NULL;
Mayank Grovera9ffe802019-06-03 14:08:40 +05302163 struct fstab_node table = target_dynamic_partition_supported() ?
2164 dynamic_fstab_table :
2165 fstab_table;
Kishor PK536904a2017-07-13 17:18:59 +05302166
2167 /* Find the parent node */
Mayank Grovera9ffe802019-06-03 14:08:40 +05302168 parent_offset = fdt_path_offset(fdt, table.parent_node);
Kishor PK536904a2017-07-13 17:18:59 +05302169 if (parent_offset < 0) {
2170 dprintf(CRITICAL, "Failed to get parent node: fstab error: %d\n", parent_offset);
2171 return -1;
2172 }
2173 dprintf(SPEW, "Node: %s found.\n", fdt_get_name(fdt, parent_offset, NULL));
2174
Mayank Grovera9ffe802019-06-03 14:08:40 +05302175 if (!target_dynamic_partition_supported())
2176 {
2177 /* Get boot device type */
2178 boot_dev_buf = (char *) malloc(sizeof(char) * BOOT_DEV_MAX_LEN);
2179 if (!boot_dev_buf) {
2180 dprintf(CRITICAL, "Failed to allocate memory for boot device\n");
2181 return -1;
2182 }
2183
2184 new_str = (char *) malloc(sizeof(char) * NODE_PROPERTY_MAX_LEN);
2185 if (!new_str) {
2186 dprintf(CRITICAL, "Failed to allocate memory for node property string\n");
2187 return -1;
2188 }
2189
2190 platform_boot_dev_cmdline(boot_dev_buf);
Kishor PK536904a2017-07-13 17:18:59 +05302191 }
2192
Kishor PK536904a2017-07-13 17:18:59 +05302193 /* Get properties of all sub nodes */
Mayank Grovera9ffe802019-06-03 14:08:40 +05302194 for (subnode_offset = fdt_first_subnode(fdt, parent_offset);
2195 subnode_offset >= 0;
2196 subnode_offset = fdt_next_subnode(fdt, subnode_offset)) {
2197 prop = fdt_get_property(fdt, subnode_offset, table.node_prop, &prop_length);
Kishor PK536904a2017-07-13 17:18:59 +05302198 node_name = (char *)(uintptr_t)fdt_get_name(fdt, subnode_offset, NULL);
2199 if (!prop) {
Mayank Grovera9ffe802019-06-03 14:08:40 +05302200 dprintf(CRITICAL, "Property:%s is not found for sub node:%s\n", table.node_prop, node_name);
Kishor PK536904a2017-07-13 17:18:59 +05302201 } else {
Mayank Grovera9ffe802019-06-03 14:08:40 +05302202 dprintf(CRITICAL, "Property:%s found for sub node:%s\tproperty:%s\n", table.node_prop, node_name, prop->data);
2203
2204 /* For Dynamic partition support disable firmware fstab nodes. */
2205 if (target_dynamic_partition_supported())
2206 {
2207 dprintf (INFO, "Disabling node status :%s\n", node_name);
2208 ret = fdt_setprop (fdt, subnode_offset, table.node_prop, "disabled",
2209 (strlen("disabled") + 1));
2210 if (ret)
2211 {
2212 dprintf(CRITICAL, "ERROR: Failed to disable Node: %s\n", node_name);
2213 }
2214 continue;
2215 }
2216
Kishor PK536904a2017-07-13 17:18:59 +05302217 /* Pointer to fdt 'dev' property string that needs to update based on the 'androidboot.bootdevice' */
2218 memset(new_str, 0, NODE_PROPERTY_MAX_LEN);
2219 prefix_str = (char *)prop->data;
2220 if (strlen(prefix_str) > NODE_PROPERTY_MAX_LEN) {
2221 dprintf(CRITICAL, "Property string length is greater than node property max length\n");
2222 continue;
2223 }
Mayank Grovera9ffe802019-06-03 14:08:40 +05302224 suffix_str = strstr(prefix_str, table.device_path_id);
Kishor PK536904a2017-07-13 17:18:59 +05302225 if (!suffix_str) {
2226 dprintf(CRITICAL, "Property is not proper to update\n");
2227 continue;
2228 }
Mayank Grovera9ffe802019-06-03 14:08:40 +05302229 suffix_str += strlen(table.device_path_id);
Kishor PK536904a2017-07-13 17:18:59 +05302230 prefix_string_len = strlen(prefix_str) - (strlen(suffix_str) - 1);
2231 suffix_str = strstr((suffix_str + 1), "/");
2232 str_len = strlcpy(new_str, prefix_str, prefix_string_len);
2233 if (!str_len) {
2234 dprintf(CRITICAL, "Property length is not proper to update\n");
2235 continue;
2236 }
2237 str_len = strlcat(new_str, boot_dev_buf, strlen(prefix_str));
2238 if (!str_len) {
2239 dprintf(CRITICAL, "Property length is not proper to update\n");
2240 continue;
2241 }
2242 str_len = strlcat(new_str, suffix_str, strlen(prefix_str));
2243 if (!str_len) {
2244 dprintf(CRITICAL, "Property length is not proper to update\n");
2245 continue;
2246 }
2247 /* Update the new property in the memory */
2248 memscpy(prefix_str, strlen(prefix_str), new_str, strlen(new_str) + 1);
2249 /* Update the property with new value */
Mayank Grovera9ffe802019-06-03 14:08:40 +05302250 ret = fdt_setprop(fdt, subnode_offset, table.node_prop, (const void *)prefix_str, strlen(prefix_str) + 1);
Kishor PK536904a2017-07-13 17:18:59 +05302251 if(ret) {
2252 dprintf(CRITICAL, "Failed to update the node with new property\n");
2253 continue;
2254 }
2255 dprintf(CRITICAL, "Updated %s with new property %s\n", node_name, prop->data);
2256 }
2257 }
2258 if (boot_dev_buf)
2259 free(boot_dev_buf);
2260 if (new_str)
2261 free(new_str);
2262 return ret;
2263}
2264#endif