blob: fa7b28ace1c55aa698659a08eaae0abf785e3e1d [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
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +0530116int fdt_check_header_ext(const void *fdt)
117{
118 uintptr_t fdt_start, fdt_end;
119 fdt_start = (uintptr_t)fdt;
120 if(fdt_start + fdt_totalsize(fdt) < fdt_start)
121 {
122 dprintf(CRITICAL,"Integer over in fdt header %s\t%d",__func__,__LINE__);
123 return FDT_ERR_BADOFFSET;
124 }
125 fdt_end = fdt_start + fdt_totalsize(fdt);
126
127 if (((uint64_t)fdt_start + (uint64_t)fdt_off_dt_struct(fdt) + (uint64_t)fdt_size_dt_struct(fdt)) > UINT_MAX)
128 return FDT_ERR_BADOFFSET;
129
130 if ((fdt_start + fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt)) > fdt_end)
131 return FDT_ERR_BADOFFSET;
132
133 if (((uint64_t)fdt_start + (uint64_t)fdt_off_dt_strings(fdt) + (uint64_t)fdt_size_dt_strings(fdt)) > UINT_MAX)
134 return FDT_ERR_BADOFFSET;
135
136 if ((fdt_start + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)) > fdt_end)
137 return FDT_ERR_BADOFFSET;
138
139 return 0;
140}
141
Shashank Mittalc0f10282013-07-15 14:53:31 -0700142/* Returns soc version if platform id and hardware id matches
143 otherwise return 0xFFFFFFFF */
144#define INVALID_SOC_REV_ID 0XFFFFFFFF
Lijuan Gao9f152862014-08-18 13:45:24 +0800145
146/* Add function to allocate dt entry list, used for recording
147* the entry which conform to platform_dt_absolute_match()
148*/
149static struct dt_entry_node *dt_entry_list_init(void)
150{
151 struct dt_entry_node *dt_node_member = NULL;
152
153 dt_node_member = (struct dt_entry_node *)
154 malloc(sizeof(struct dt_entry_node));
155
156 ASSERT(dt_node_member);
157
158 list_clear_node(&dt_node_member->node);
159 dt_node_member->dt_entry_m = (struct dt_entry *)
160 malloc(sizeof(struct dt_entry));
161 ASSERT(dt_node_member->dt_entry_m);
162
163 memset(dt_node_member->dt_entry_m ,0 ,sizeof(struct dt_entry));
164 return dt_node_member;
165}
166
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530167/*
168 * Function to validate dtbo image.
169 * return: TRUE or FALSE.
170 */
Mayank Groverb61c0c22018-09-04 15:09:32 +0530171dtbo_error load_validate_dtbo_image(void **dtbo_buf, uint32_t *dtbo_image_sz)
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530172{
173 uint64_t dtbo_total_size = 0;
Mayank Groverb61c0c22018-09-04 15:09:32 +0530174 static void *dtbo_image_buf = NULL;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530175 unsigned int dtbo_image_buf_size;
176 unsigned int dtbo_partition_size;
Mayank Groverb61c0c22018-09-04 15:09:32 +0530177 unsigned long long ptn, boot_img_sz;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530178 int index = INVALID_PTN;
179 int page_size = mmc_page_size();
180 struct dtbo_table_hdr *dtbo_table_header = NULL;
181 dtbo_error ret = DTBO_SUCCESS;
Mayank Groverb61c0c22018-09-04 15:09:32 +0530182 static bool dtbo_loaded = false;
183 static unsigned long long ptn_size = 0;
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530184 uint32_t recovery_dtbo_size = 0;
185 void *recovery_appended_dtbo = NULL;
Mayank Groverb61c0c22018-09-04 15:09:32 +0530186
187 /* If dtbo loaded skip loading */
188 if (dtbo_loaded)
189 goto out;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530190
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530191 get_recovery_dtbo_info(&recovery_dtbo_size, &recovery_appended_dtbo);
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530192
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530193 /* Intialize dtbo for recovery header v1 */
194 if (recovery_dtbo_size && recovery_appended_dtbo) {
195 dtbo_image_buf = recovery_appended_dtbo;
196 dtbo_partition_size = recovery_dtbo_size;
197 ptn_size = recovery_dtbo_size;
198 } else {
199 index = partition_get_index("dtbo");
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530200
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530201
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530202 /* Immediately return if dtbo is not supported */
203 if (index == INVALID_PTN)
204 {
205 ret = DTBO_NOT_SUPPORTED;
206 goto out;
207 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530208
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530209 ptn = partition_get_offset(index);
210 if(!ptn)
211 {
212 dprintf(CRITICAL, "ERROR: dtbo parition failed to get offset. \n");
213 ret = DTBO_ERROR;
214 goto out;
215 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530216
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530217 ptn_size = partition_get_size(index);
218 if (ptn_size > MAX_SUPPORTED_DTBO_IMG_BUF)
219 {
220 dprintf(CRITICAL, "ERROR: dtbo parition size is greater than supported.\n");
221 ret = DTBO_ERROR;
222 goto out;
223 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530224
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530225 /*
226 Read dtbo image into scratch region after kernel image.
227 dtbo_image_buf_size = total_scratch_region_size - boot_img_sz
228 */
229 boot_img_sz = partition_get_size(partition_get_index("boot"));
230 if (!boot_img_sz)
231 {
232 dprintf(CRITICAL, "ERROR: Unable to get boot partition size\n");
233 ret = DTBO_NOT_SUPPORTED;
234 goto out;
235 }
236
237 dtbo_image_buf_size = target_get_max_flash_size() - boot_img_sz;
238 dtbo_partition_size = ptn_size + ADDR_ALIGNMENT;
239 dtbo_partition_size = ROUND_TO_PAGE(dtbo_partition_size, (page_size - 1)); /* Maximum dtbo size possible */
240 if (dtbo_partition_size == UINT_MAX ||
241 dtbo_image_buf_size < dtbo_partition_size)
242 {
243 dprintf(CRITICAL, "ERROR: Invalid DTBO partition size\n");
244 ret = DTBO_NOT_SUPPORTED;
245 goto out;
246 }
247
248 mmc_set_lun(partition_get_lun(index));
249 /* read dtbo at last 10MB of scratch */
250 dtbo_image_buf = target_get_scratch_address() +
251 (target_get_max_flash_size() - DTBO_IMG_BUF);
252 dtbo_image_buf =
Mayank Grover8f46a892018-09-10 13:24:59 +0530253 (void *)ROUND_TO_PAGE((addr_t)dtbo_image_buf, (ADDR_ALIGNMENT-1));
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530254 if(dtbo_image_buf == (void *)UINT_MAX)
255 {
256 dprintf(CRITICAL, "ERROR: Invalid DTBO image buf addr\n");
257 ret = DTBO_NOT_SUPPORTED;
258 goto out;
259 }
260
Mayank Grover8f46a892018-09-10 13:24:59 +0530261 /* Add offset for salt buffer for verification */
262 dtbo_image_buf += SALT_BUFF_OFFSET;
Mayank Grover3dcc95b2018-09-04 20:31:38 +0530263 /* Read dtbo partition with header */
264 if (mmc_read(ptn, (uint32_t *)(dtbo_image_buf), dtbo_partition_size))
265 {
266 dprintf(CRITICAL, "ERROR: dtbo partition mmc read failure \n");
267 ret = DTBO_ERROR;
268 goto out;
269 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530270 }
271
272 /* validate the dtbo image, before reading complete image */
273 dtbo_table_header = (struct dtbo_table_hdr *)dtbo_image_buf;
274
275 /*Check for dtbo magic*/
276 if (fdt32_to_cpu(dtbo_table_header->magic) != DTBO_TABLE_MAGIC)
277 {
278 dprintf(CRITICAL, "dtbo header magic mismatch %x, with %x\n",
279 fdt32_to_cpu(dtbo_table_header->magic), DTBO_TABLE_MAGIC);
280 ret = DTBO_ERROR;
281 goto out;
282 }
283
284 /*Check for dtbo image table size*/
285 if (fdt32_to_cpu(dtbo_table_header->hdr_size) != sizeof(struct dtbo_table_hdr))
286 {
287 dprintf(CRITICAL, "dtbo table header size got corrupted\n");
288 ret = DTBO_ERROR;
289 goto out;
290 }
291
292 /*Check for dt entry size of dtbo image*/
293 if (fdt32_to_cpu(dtbo_table_header->dt_entry_size) != sizeof(struct dtbo_table_entry))
294 {
295 dprintf(CRITICAL, "dtbo table dt entry size got corrupted\n");
296 ret = DTBO_ERROR;
297 goto out;
298 }
299
300 /*Total size of dtbo */
301 dtbo_total_size = fdt32_to_cpu(dtbo_table_header->total_size);
302 if (dtbo_total_size > dtbo_partition_size || dtbo_total_size == 0)
303 {
304 dprintf(CRITICAL, "dtbo table total size exceeded the dtbo buffer allocated\n");
305 ret = DTBO_ERROR;
306 goto out;
307 }
308
309 /* Total size of dtbo entries */
310 dtbo_total_size = fdt32_to_cpu(dtbo_table_header->dt_entry_count) *
311 fdt32_to_cpu(dtbo_table_header->dt_entry_size);
312 if (dtbo_total_size > dtbo_partition_size || dtbo_total_size == 0)
313 {
314 dprintf(CRITICAL, "dtbo table total size exceeded the dtbo buffer allocated\n");
315 ret = DTBO_ERROR;
316 goto out;
317 }
318
319 /* Offset should be less than image size */
320 if (fdt32_to_cpu(dtbo_table_header->dt_entry_offset) > dtbo_partition_size)
321 {
322 dprintf(CRITICAL, "dtbo offset exceeds the dtbo buffer allocated\n");
323 ret = DTBO_ERROR;
324 goto out;
325 }
326
327 /* Offset + total size is less than image size */
328 if (dtbo_total_size + fdt32_to_cpu(dtbo_table_header->dt_entry_offset) > dtbo_partition_size)
329 {
330 dprintf(CRITICAL, "dtbo size exceeded the dtbo buffer allocated\n");
331 ret = DTBO_ERROR;
332 }
333
334out:
Mayank Groverb61c0c22018-09-04 15:09:32 +0530335 if (ret == DTBO_SUCCESS)
336 {
337 *dtbo_buf = dtbo_image_buf;
338 *dtbo_image_sz = (uint32_t)ptn_size;
339 dtbo_loaded = true;
340 }
341 else
342 {
343 *dtbo_buf = NULL;
344 *dtbo_image_sz = 0;
345 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530346 return ret;
347}
348
349static bool check_all_bits_set(uint32_t matchdt_value)
350{
351 return (matchdt_value & ALL_BITS_SET) == (ALL_BITS_SET);
352}
353
354/* Dt selection table for quick reference
355 | SNO | Dt Property | CDT Property | Exact | Best | Default |
356 |-----+---------------+-----------------+-------+------+---------+
357 | | qcom, msm-id | | | | |
358 | | | PlatformId | Y | N | N |
359 | | | SocRev | N | Y | N |
360 | | | FoundryId | Y | N | 0 |
361 | | qcom,board-id | | | | |
362 | | | VariantId | Y | N | N |
363 | | | VariantMajor | N | Y | N |
364 | | | VariantMinor | N | Y | N |
365 | | | PlatformSubtype | Y | N | 0 |
366 | | qcom,pmic-id | | | | |
367 | | | PmicModelId | Y | N | 0 |
368 | | | PmicMetalRev | N | Y | N |
369 | | | PmicLayerRev | N | Y | N |
370 | | | PmicVariantRev | N | Y | N |
371*/
372
lijuang0cce8bf2018-08-23 10:56:42 +0800373static 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 +0530374{
375 int board_id_len;
376 int platform_id_len = 0;
377 int pmic_id_len;
378 int root_offset = 0;
379 void *dtb = current_dtb_info->dtb;
380 uint32_t idx;
381 const char *platform_prop = NULL;
382 const char *board_prop = NULL;
383 const char *pmic_prop = NULL;
lijuang0cce8bf2018-08-23 10:56:42 +0800384 boolean find_best_match = false;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530385
386 current_dtb_info->dt_match_val = 0;
387 root_offset = fdt_path_offset(dtb, "/");
388 if (root_offset < 0) {
389 dprintf(CRITICAL, "ERROR: Unable to locate root node\n");
lijuang0cce8bf2018-08-23 10:56:42 +0800390 return false;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530391 }
392
393 /* Get the msm-id prop from DTB and find best match */
394 platform_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,msm-id", &platform_id_len);
395 if (platform_prop && (platform_id_len > 0) && (!(platform_id_len % PLAT_ID_SIZE))) {
396 /*Compare msm-id of the dtb vs board*/
397 current_dtb_info->dt_platform_id = fdt32_to_cpu(((struct plat_id *)platform_prop)->platform_id);
398 dprintf(SPEW, "Board SOC ID = %x | DT SOC ID = %x\n", (board_platform_id() & SOC_MASK),
399 (current_dtb_info->dt_platform_id & SOC_MASK));
400 if ((board_platform_id() & SOC_MASK) == (current_dtb_info->dt_platform_id & SOC_MASK)) {
401 current_dtb_info->dt_match_val |= BIT(SOC_MATCH);
402 } else {
403 dprintf(SPEW, "qcom,msm-id does not match\n");
404 /* If soc doesn't match, don't select dtb */
405 current_dtb_info->dt_match_val = BIT(NONE_MATCH);
406 goto cleanup;
407 }
408 /*Compare soc rev of the dtb vs board*/
409 current_dtb_info->dt_soc_rev = fdt32_to_cpu(((struct plat_id *)platform_prop)->soc_rev);
410 dprintf(SPEW, "Board SOC Rev = %x | DT SOC Rev =%x\n", board_soc_version(),
411 current_dtb_info->dt_soc_rev);
412 if (current_dtb_info->dt_soc_rev == board_soc_version()) {
413 current_dtb_info->dt_match_val |= BIT(VERSION_EXACT_MATCH);
414 } else if (current_dtb_info->dt_soc_rev < board_soc_version()) {
415 current_dtb_info->dt_match_val |= BIT(VERSION_BEST_MATCH);
416 } else if (current_dtb_info->dt_soc_rev) {
417 dprintf(SPEW, "SOC version does not match\n");
418 }
419 /*Compare Foundry Id of the dtb vs Board*/
420 current_dtb_info->dt_foundry_id = fdt32_to_cpu(((struct plat_id *)platform_prop)->platform_id) & FOUNDRY_ID_MASK;
421 dprintf (SPEW, "Board Foundry id = %x | DT Foundry id = %x\n", (board_foundry_id() << PLATFORM_FOUNDRY_SHIFT), current_dtb_info->dt_foundry_id);
422 if (current_dtb_info->dt_foundry_id == (board_foundry_id() << PLATFORM_FOUNDRY_SHIFT)) {
423 current_dtb_info->dt_match_val |= BIT (FOUNDRYID_EXACT_MATCH);
424 } else if (current_dtb_info->dt_foundry_id == 0 ){
425 current_dtb_info->dt_match_val |= BIT (FOUNDRYID_DEFAULT_MATCH);
426 } else {
427 dprintf(SPEW, "soc foundry does not match\n");
428 /* If soc doesn't match, don't select dtb */
429 current_dtb_info->dt_match_val = BIT(NONE_MATCH);
430 goto cleanup;
431 }
432 } else {
433 dprintf(SPEW, "qcom,msm-id does not exist (or) is (%d) not a multiple of (%d)\n", platform_id_len, PLAT_ID_SIZE);
434 }
435
436 /* Get the properties like variant id, subtype from DTB and compare the DTB vs Board */
437 board_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,board-id", &board_id_len);
438 if (board_prop && (board_id_len > 0) && (!(board_id_len % BOARD_ID_SIZE))) {
439 current_dtb_info->dt_variant_id = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id);
440 current_dtb_info->dt_platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->platform_subtype);
441 if (current_dtb_info->dt_platform_subtype == 0)
442 current_dtb_info->dt_platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id) >> PLATFORM_SUBTYPE_SHIFT_ID;
443
444 dprintf(SPEW, "Board variant id = %x | DT variant id = %x\n",board_hardware_id(), current_dtb_info->dt_variant_id);
445
446 current_dtb_info->dt_variant_major = current_dtb_info->dt_variant_id & VARIANT_MAJOR_MASK;
447 current_dtb_info->dt_variant_minor = current_dtb_info->dt_variant_id & VARIANT_MINOR_MASK;
448 current_dtb_info->dt_variant_id = current_dtb_info->dt_variant_id & VARIANT_MASK;
449
450 if (current_dtb_info->dt_variant_id == board_hardware_id()) {
451 current_dtb_info->dt_match_val |= BIT(VARIANT_MATCH);
452 } else if (current_dtb_info->dt_variant_id) {
453 dprintf(SPEW, "qcom,board-id doesnot match\n");
454 /* If board variant doesn't match, don't select dtb */
455 current_dtb_info->dt_match_val = BIT(NONE_MATCH);
456 goto cleanup;
457 }
458
459 if (current_dtb_info->dt_variant_major == (board_target_id() & VARIANT_MAJOR_MASK)) {
460 current_dtb_info->dt_match_val |= BIT(VARIANT_MAJOR_EXACT_MATCH);
461 } else if (current_dtb_info->dt_variant_major < (board_target_id() & VARIANT_MAJOR_MASK)) {
462 current_dtb_info->dt_match_val |= BIT(VARIANT_MAJOR_BEST_MATCH);
463 } else if (current_dtb_info->dt_variant_major) {
464 dprintf(SPEW, "qcom,board-id major version doesnot match\n");
465 }
466
467 if (current_dtb_info->dt_variant_minor == (board_target_id() & VARIANT_MINOR_MASK)) {
468 current_dtb_info->dt_match_val |= BIT(VARIANT_MINOR_EXACT_MATCH);
469 } else if (current_dtb_info->dt_variant_minor < (board_target_id() & VARIANT_MINOR_MASK)) {
470 current_dtb_info->dt_match_val |= BIT(VARIANT_MINOR_BEST_MATCH);
471 } else if (current_dtb_info->dt_variant_minor) {
472 dprintf(SPEW, "qcom,board-id minor version doesnot match\n");
473 }
474
475 dprintf(SPEW, "Board platform subtype = %x | DT platform subtype = %x\n",
476 board_hardware_subtype(), current_dtb_info->dt_platform_subtype);
477 if (current_dtb_info->dt_platform_subtype == board_hardware_subtype()) {
478 current_dtb_info->dt_match_val |= BIT(SUBTYPE_EXACT_MATCH);
479 } else if (current_dtb_info->dt_platform_subtype == 0) {
480 current_dtb_info->dt_match_val |= BIT(SUBTYPE_DEFAULT_MATCH);
481 } else if (current_dtb_info->dt_platform_subtype) {
482 dprintf(SPEW, "subtype id doesnot match\n");
483 /* If board platform doesn't match, don't select dtb */
484 current_dtb_info->dt_match_val = BIT(NONE_MATCH);
485 goto cleanup;
486 }
487 } else {
488 dprintf(SPEW, "qcom,board-id does not exist (or)(%d) is not a multiple of (%d)\n",
489 board_id_len, BOARD_ID_SIZE);
490 }
491
492 /* Get the pmic property from DTB then compare the DTB vs Board */
493 pmic_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,pmic-id", &pmic_id_len);
494 if (pmic_prop && (pmic_id_len > 0) && (!(pmic_id_len % sizeof(struct pmic_id))))
495 {
496 pmic_info curr_pmic_info;
497 pmic_info best_pmic_info;
498 unsigned int pmic_entry_indx;
499 unsigned int pmic_entries_count;
500
501 /* Find all pmic entries count */
502 pmic_entries_count = pmic_id_len/sizeof(struct pmic_id);
503
504 memset(&best_pmic_info, 0, sizeof(pmic_info));
505 for (pmic_entry_indx = 0; pmic_entry_indx < pmic_entries_count; pmic_entry_indx++)
506 {
507 memset(&curr_pmic_info, 0, sizeof(pmic_info));
508
509 /* Read all pmic info */
510 /* Compare with board pmic */
511 for (idx = 0; idx < MAX_PMIC_IDX; idx++)
512 {
513 curr_pmic_info.dt_pmic_model[idx] =
514 fdt32_to_cpu (((struct pmic_id *)pmic_prop)->pmic_version[idx]);
515 dprintf(SPEW, "pmic_data[%u]:%x\n", idx, curr_pmic_info.dt_pmic_model[idx]);
516 curr_pmic_info.dt_pmic_rev[idx] =
517 curr_pmic_info.dt_pmic_model[idx] & PMIC_REV_MASK;
518 curr_pmic_info.dt_pmic_model[idx] =
519 curr_pmic_info.dt_pmic_model[idx] & PMIC_MODEL_MASK;
520
521 /* Compare with board pmic information & Update bit mask */
522 if (curr_pmic_info.dt_pmic_model[idx] == (board_pmic_target(idx) & PMIC_MODEL_MASK))
523 curr_pmic_info.dt_match_val |= BIT (PMIC_MATCH_EXACT_MODEL_IDX0 + idx * PMIC_SHIFT_IDX);
524 else if (curr_pmic_info.dt_pmic_model[idx] == 0)
525 curr_pmic_info.dt_match_val |= BIT (PMIC_MATCH_DEFAULT_MODEL_IDX0 + idx * PMIC_SHIFT_IDX);
526 else
527 {
528 curr_pmic_info.dt_match_val |= BIT (NONE_MATCH);
529 dprintf(SPEW, "PMIC Model doesn't match\n");
530 break; /* go to next pmic entry */
531 }
532
533 if (curr_pmic_info.dt_pmic_rev[idx] == (board_pmic_target(idx) & PMIC_REV_MASK))
534 curr_pmic_info.dt_match_val |= BIT(PMIC_MATCH_EXACT_REV_IDX0 + idx * PMIC_SHIFT_IDX);
535 else if (curr_pmic_info.dt_pmic_rev[idx] < (board_pmic_target(idx) & PMIC_REV_MASK))
536 curr_pmic_info.dt_match_val |= BIT(PMIC_MATCH_BEST_REV_IDX0 + idx * PMIC_SHIFT_IDX);
lijuangf1b8e1d2018-03-01 14:40:37 +0800537 else {
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530538 dprintf(SPEW, "PMIC revision doesn't match\n");
539 break; /* go to next pmic entry */
lijuangf1b8e1d2018-03-01 14:40:37 +0800540 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530541 }
542
543 dprintf(SPEW, "Bestpmicinfo.dtmatchval : %x | cur_pmic_info.dtmatchval: %x\n",
544 best_pmic_info.dt_match_val, curr_pmic_info.dt_match_val);
545
546 /* Update best pmic info, if required */
547 if(best_pmic_info.dt_match_val < curr_pmic_info.dt_match_val)
548 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
549 else if (best_pmic_info.dt_match_val == curr_pmic_info.dt_match_val)
550 {
551 if (best_pmic_info.dt_pmic_rev[PMIC_IDX0] < curr_pmic_info.dt_pmic_rev[PMIC_IDX0])
552 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
553 else if (best_pmic_info.dt_pmic_rev[PMIC_IDX1] < curr_pmic_info.dt_pmic_rev[PMIC_IDX1])
554 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
555 else if (best_pmic_info.dt_pmic_rev[PMIC_IDX2] < curr_pmic_info.dt_pmic_rev[PMIC_IDX2])
556 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
557 else if (best_pmic_info.dt_pmic_rev[PMIC_IDX3] < curr_pmic_info.dt_pmic_rev[PMIC_IDX3])
558 memscpy(&best_pmic_info, sizeof(pmic_info), &curr_pmic_info, sizeof(pmic_info));
559 }
560
561 /* Increment to next pmic entry */
562 pmic_prop += sizeof (struct pmic_id);
563 }
564
565 dprintf(SPEW, "Best pmic info 0x%0x/0x%x/0x%x/0x%0x for current dt\n",
566 best_pmic_info.dt_pmic_model[PMIC_IDX0],
567 best_pmic_info.dt_pmic_model[PMIC_IDX1],
568 best_pmic_info.dt_pmic_model[PMIC_IDX2],
569 best_pmic_info.dt_pmic_model[PMIC_IDX3]);
570
571 current_dtb_info->dt_match_val |= best_pmic_info.dt_match_val;
572 current_dtb_info->dt_pmic_rev[PMIC_IDX0] = best_pmic_info.dt_pmic_rev[PMIC_IDX0];
573 current_dtb_info->dt_pmic_model[PMIC_IDX0] = best_pmic_info.dt_pmic_model[PMIC_IDX0];
574 current_dtb_info->dt_pmic_rev[PMIC_IDX1] = best_pmic_info.dt_pmic_rev[PMIC_IDX1];
575 current_dtb_info->dt_pmic_model[PMIC_IDX1] = best_pmic_info.dt_pmic_model[PMIC_IDX1];
576 current_dtb_info->dt_pmic_rev[PMIC_IDX2] = best_pmic_info.dt_pmic_rev[PMIC_IDX2];
577 current_dtb_info->dt_pmic_model[PMIC_IDX2] = best_pmic_info.dt_pmic_model[PMIC_IDX2];
578 current_dtb_info->dt_pmic_rev[PMIC_IDX3] = best_pmic_info.dt_pmic_rev[PMIC_IDX3];
579 current_dtb_info->dt_pmic_model[PMIC_IDX3] = best_pmic_info.dt_pmic_model[PMIC_IDX3];
580 }
581 else
582 {
583 dprintf(SPEW, "qcom,pmic-id does not exit (or) is (%d) not a multiple of (%d)\n",
584 pmic_id_len, PMIC_ID_SIZE);
585 }
586
587cleanup:
588 if (current_dtb_info->dt_match_val & BIT(exact_match)) {
lijuang0cce8bf2018-08-23 10:56:42 +0800589 if (best_dtb_info->dt_match_val < current_dtb_info->dt_match_val) {
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530590 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
lijuang0cce8bf2018-08-23 10:56:42 +0800591 find_best_match = true;
592 } else if (best_dtb_info->dt_match_val == current_dtb_info->dt_match_val) {
593 find_best_match = true;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530594 if (best_dtb_info->dt_soc_rev < current_dtb_info->dt_soc_rev)
595 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
596 else if (best_dtb_info->dt_variant_major < current_dtb_info->dt_variant_major)
597 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
598 else if (best_dtb_info->dt_variant_minor < current_dtb_info->dt_variant_minor)
599 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
600 else if (best_dtb_info->dt_pmic_rev[0] < current_dtb_info->dt_pmic_rev[0])
601 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
602 else if (best_dtb_info->dt_pmic_rev[1] < current_dtb_info->dt_pmic_rev[1])
603 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
604 else if (best_dtb_info->dt_pmic_rev[2] < current_dtb_info->dt_pmic_rev[2])
605 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
606 else if (best_dtb_info->dt_pmic_rev[3] < current_dtb_info->dt_pmic_rev[3])
607 memscpy(best_dtb_info, sizeof(dt_info), current_dtb_info, sizeof(dt_info));
lijuang0cce8bf2018-08-23 10:56:42 +0800608 else
609 find_best_match = false;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530610 }
611 }
lijuang0cce8bf2018-08-23 10:56:42 +0800612
613 return find_best_match;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530614}
615
616void *get_soc_dtb(void *kernel, uint32_t kernel_size, uint32_t dtb_offset)
617{
618 uintptr_t kernel_end_offset = (uintptr_t)kernel + kernel_size;
619 void *dtb = NULL;
620 struct fdt_header dtb_header;
621 uint32_t dtb_size = 0;
622 dt_info cur_dtb_info = {0};
623 dt_info best_dtb_info = {0};
624
625 if (!dtb_offset){
626 dprintf(CRITICAL, "DTB offset is NULL\n");
627 return NULL;
628 }
629 if (((uintptr_t)kernel + (uintptr_t)dtb_offset) < (uintptr_t)kernel) {
630 return NULL;
631 }
632 dtb = kernel + dtb_offset;
633 while (((uintptr_t)dtb + sizeof(struct fdt_header)) < (uintptr_t)kernel_end_offset) {
634 /* the DTB could be unaligned, so extract the header,
635 * and operate on it separately */
636 memscpy(&dtb_header, sizeof(struct fdt_header), dtb, sizeof(struct fdt_header));
637 dtb_size = fdt_totalsize((const void *)&dtb_header);
638 if (fdt_check_header((const void *)&dtb_header) != 0 ||
639 fdt_check_header_ext((void *)&dtb_header) != 0 ||
640 ((uintptr_t)dtb + dtb_size < (uintptr_t)dtb) ||
641 ((uintptr_t)dtb + dtb_size > (uintptr_t)kernel_end_offset))
642 break;
643
644 cur_dtb_info.dtb = dtb;
645 dtb_read_find_match(&cur_dtb_info, &best_dtb_info, SOC_MATCH);
646 if (cur_dtb_info.dt_match_val) {
647 if (cur_dtb_info.dt_match_val & BIT(SOC_MATCH)) {
648 if (check_all_bits_set(cur_dtb_info.dt_match_val)) {
649 dprintf(CRITICAL, "Exact DTB match found. dtbo search is not required\n");
650 dtbo_needed = false;
651 }
652 }
653 }
654 dprintf(SPEW, "Best Match DTB VAL = %x\n", best_dtb_info.dt_match_val);
655 dtb += dtb_size;
656 }
657 if (!best_dtb_info.dtb) {
658 dprintf(CRITICAL, "No match found for soc dtb type\n");
659 return NULL;
660 }
661 return best_dtb_info.dtb;
662}
663
664void *get_board_dtb(void *dtbo_image_buf)
665{
666 struct dtbo_table_hdr *dtbo_table_header = dtbo_image_buf;
667 struct dtbo_table_entry *dtb_table_entry = NULL;
668 uint32_t dtbo_count = 0;
669 void *board_dtb = NULL;
670 uint32_t dtbo_table_entries_count = 0;
671 uint32_t first_dtbo_table_entry_offset = 0;
672 struct fdt_header dtb_header;
673 uint32_t dtb_size = 0;
674 dt_info cur_dtb_info = {0};
675 dt_info best_dtb_info = {0};
lijuang0cce8bf2018-08-23 10:56:42 +0800676 boolean find_best_dtb = false;
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530677
678 if (!dtbo_image_buf) {
679 dprintf(CRITICAL, "dtbo image buffer is NULL\n");
680 return NULL;
681 }
682
683 first_dtbo_table_entry_offset = fdt32_to_cpu(dtbo_table_header->dt_entry_offset);
684 if ((uintptr_t)dtbo_image_buf > ((uintptr_t)dtbo_image_buf + (uintptr_t)first_dtbo_table_entry_offset))
685 {
686 dprintf(CRITICAL, "dtbo table entry offset is invalid\n");
687 return NULL;
688 }
689 dtb_table_entry = (struct dtbo_table_entry *)(dtbo_image_buf + first_dtbo_table_entry_offset);
690 dtbo_table_entries_count = fdt32_to_cpu(dtbo_table_header->dt_entry_count);
691 for (dtbo_count = 0; dtbo_count < dtbo_table_entries_count; dtbo_count++) {
692 board_dtb = dtbo_image_buf + fdt32_to_cpu(dtb_table_entry->dt_offset);
693 /* The DTB could be unaligned, so extract the header,
694 * and operate on it separately */
695 memscpy(&dtb_header, sizeof(struct fdt_header), board_dtb, sizeof(struct fdt_header));
696 dtb_size = fdt_totalsize((const void *)&dtb_header);
697 if (fdt_check_header((const void *)&dtb_header) != 0 ||
698 fdt_check_header_ext((void *)&dtb_header) != 0 ||
699 ((uintptr_t)board_dtb + dtb_size < (uintptr_t)board_dtb)) {
700 dprintf(CRITICAL, "No valid board dtb found\n");
701 break;
702 }
703 dprintf(SPEW, "Valid board dtb is found\n");
704 cur_dtb_info.dtb = board_dtb;
lijuang0cce8bf2018-08-23 10:56:42 +0800705 find_best_dtb = dtb_read_find_match(&cur_dtb_info, &best_dtb_info, VARIANT_MATCH);
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530706 dprintf(SPEW, "dtbo count = %u local_board_dt_match =%x\n",dtbo_count, cur_dtb_info.dt_match_val);
707 dtb_table_entry++;
lijuang0cce8bf2018-08-23 10:56:42 +0800708
709 if (find_best_dtb) {
710 dtbo_idx = dtbo_count;
711 }
Mayank Grover1b6da5d2017-12-19 16:05:46 +0530712 }
713 if (!best_dtb_info.dtb) {
714 dprintf(CRITICAL, "Unable to find the board dtb\n");
715 return NULL;
716 }
717 return best_dtb_info.dtb;
718}
719
Lijuan Gao9f152862014-08-18 13:45:24 +0800720static void insert_dt_entry_in_queue(struct dt_entry_node *dt_list, struct dt_entry_node *dt_node_member)
721{
722 list_add_tail(&dt_list->node, &dt_node_member->node);
723}
724
725static void dt_entry_list_delete(struct dt_entry_node *dt_node_member)
726{
727 if (list_in_list(&dt_node_member->node)) {
728 list_delete(&dt_node_member->node);
729 free(dt_node_member->dt_entry_m);
730 free(dt_node_member);
731 }
732}
733
734static int dev_tree_compatible(void *dtb, uint32_t dtb_size, struct dt_entry_node *dtb_list)
Dima Zavinc46f8382013-05-03 12:23:06 -0700735{
736 int root_offset;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700737 const void *prop = NULL;
738 const char *plat_prop = NULL;
739 const char *board_prop = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800740 const char *pmic_prop = NULL;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700741 char *model = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800742 struct dt_entry *cur_dt_entry;
743 struct dt_entry *dt_entry_array = NULL;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700744 struct board_id *board_data = NULL;
745 struct plat_id *platform_data = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800746 struct pmic_id *pmic_data = NULL;
Dima Zavinc46f8382013-05-03 12:23:06 -0700747 int len;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700748 int len_board_id;
749 int len_plat_id;
750 int min_plat_id_len = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800751 int len_pmic_id;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700752 uint32_t dtb_ver;
753 uint32_t num_entries = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800754 uint32_t i, j, k, n;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700755 uint32_t msm_data_count;
756 uint32_t board_data_count;
Lijuan Gao9f152862014-08-18 13:45:24 +0800757 uint32_t pmic_data_count;
Dima Zavinc46f8382013-05-03 12:23:06 -0700758
759 root_offset = fdt_path_offset(dtb, "/");
760 if (root_offset < 0)
761 return false;
762
763 prop = fdt_getprop(dtb, root_offset, "model", &len);
764 if (prop && len > 0) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700765 model = (char *) malloc(sizeof(char) * len);
766 ASSERT(model);
767 strlcpy(model, prop, len);
Dima Zavinc46f8382013-05-03 12:23:06 -0700768 } else {
vijay kumar89d36d82014-06-30 19:32:18 +0530769 dprintf(INFO, "model does not exist in device tree\n");
Dima Zavinc46f8382013-05-03 12:23:06 -0700770 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800771 /* Find the pmic-id prop from DTB , if pmic-id is present then
772 * the DTB is version 3, otherwise find the board-id prop from DTB ,
773 * if board-id is present then the DTB is version 2 */
774 pmic_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,pmic-id", &len_pmic_id);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700775 board_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,board-id", &len_board_id);
Lijuan Gao9f152862014-08-18 13:45:24 +0800776 if (pmic_prop && (len_pmic_id > 0) && board_prop && (len_board_id > 0)) {
777 if ((len_pmic_id % PMIC_ID_SIZE) || (len_board_id % BOARD_ID_SIZE))
778 {
779 dprintf(CRITICAL, "qcom,pmic-id(%d) or qcom,board-id(%d) in device tree is not a multiple of (%d %d)\n",
780 len_pmic_id, len_board_id, PMIC_ID_SIZE, BOARD_ID_SIZE);
781 return false;
782 }
783 dtb_ver = DEV_TREE_VERSION_V3;
784 min_plat_id_len = PLAT_ID_SIZE;
785 } else if (board_prop && len_board_id > 0) {
vijay kumar89d36d82014-06-30 19:32:18 +0530786 if (len_board_id % BOARD_ID_SIZE)
787 {
788 dprintf(CRITICAL, "qcom,board-id in device tree is (%d) not a multiple of (%d)\n",
789 len_board_id, BOARD_ID_SIZE);
790 return false;
791 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700792 dtb_ver = DEV_TREE_VERSION_V2;
793 min_plat_id_len = PLAT_ID_SIZE;
Lijuan Gao9f152862014-08-18 13:45:24 +0800794 } else {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700795 dtb_ver = DEV_TREE_VERSION_V1;
796 min_plat_id_len = DT_ENTRY_V1_SIZE;
797 }
798
799 /* Get the msm-id prop from DTB */
800 plat_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,msm-id", &len_plat_id);
801 if (!plat_prop || len_plat_id <= 0) {
Dima Zavinc46f8382013-05-03 12:23:06 -0700802 dprintf(INFO, "qcom,msm-id entry not found\n");
803 return false;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700804 } else if (len_plat_id % min_plat_id_len) {
805 dprintf(INFO, "qcom,msm-id in device tree is (%d) not a multiple of (%d)\n",
806 len_plat_id, min_plat_id_len);
Dima Zavinc46f8382013-05-03 12:23:06 -0700807 return false;
808 }
Dima Zavinc46f8382013-05-03 12:23:06 -0700809
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700810 /*
811 * If DTB version is '1' look for <x y z> pair in the DTB
812 * x: platform_id
813 * y: variant_id
814 * z: SOC rev
815 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800816 if (dtb_ver == DEV_TREE_VERSION_V1) {
817 cur_dt_entry = (struct dt_entry *)
818 malloc(sizeof(struct dt_entry));
Dima Zavinc46f8382013-05-03 12:23:06 -0700819
Lijuan Gao9f152862014-08-18 13:45:24 +0800820 if (!cur_dt_entry) {
821 dprintf(CRITICAL, "Out of memory\n");
822 return false;
823 }
824 memset(cur_dt_entry, 0, sizeof(struct dt_entry));
825
826 while (len_plat_id) {
827 cur_dt_entry->platform_id = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->platform_id);
828 cur_dt_entry->variant_id = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->variant_id);
829 cur_dt_entry->soc_rev = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->soc_rev);
830 cur_dt_entry->board_hw_subtype =
831 fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->variant_id) >> 0x18;
832 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
833 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
834 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
835 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
836 cur_dt_entry->offset = (uint32_t)dtb;
837 cur_dt_entry->size = dtb_size;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700838
839 dprintf(SPEW, "Found an appended flattened device tree (%s - %u %u 0x%x)\n",
Lijuan Gao9f152862014-08-18 13:45:24 +0800840 *model ? model : "unknown",
841 cur_dt_entry->platform_id, cur_dt_entry->variant_id, cur_dt_entry->soc_rev);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700842
Lijuan Gao9f152862014-08-18 13:45:24 +0800843 if (platform_dt_absolute_match(cur_dt_entry, dtb_list)) {
844 dprintf(SPEW, "Device tree exact match the board: <%u %u 0x%x> != <%u %u 0x%x>\n",
845 cur_dt_entry->platform_id,
846 cur_dt_entry->variant_id,
847 cur_dt_entry->soc_rev,
848 board_platform_id(),
849 board_hardware_id(),
850 board_soc_version());
851
852 } else {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700853 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 +0800854 cur_dt_entry->platform_id,
855 cur_dt_entry->variant_id,
856 cur_dt_entry->soc_rev,
857 board_platform_id(),
858 board_hardware_id(),
859 board_soc_version());
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700860 plat_prop += DT_ENTRY_V1_SIZE;
861 len_plat_id -= DT_ENTRY_V1_SIZE;
862 continue;
863 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700864 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800865 free(cur_dt_entry);
866
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700867 }
868 /*
Lijuan Gao9f152862014-08-18 13:45:24 +0800869 * If DTB Version is '3' then we have split DTB with board & msm data & pmic
870 * populated saperately in board-id & msm-id & pmic-id prop respectively.
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700871 * Extract the data & prepare a look up table
872 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800873 else if (dtb_ver == DEV_TREE_VERSION_V2 || dtb_ver == DEV_TREE_VERSION_V3) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700874 board_data_count = (len_board_id / BOARD_ID_SIZE);
875 msm_data_count = (len_plat_id / PLAT_ID_SIZE);
Lijuan Gao9f152862014-08-18 13:45:24 +0800876 /* If dtb version is v2.0, the pmic_data_count will be <= 0 */
877 pmic_data_count = (len_pmic_id / PMIC_ID_SIZE);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700878
Lijuan Gao9f152862014-08-18 13:45:24 +0800879 /* If we are using dtb v3.0, then we have split board, msm & pmic data in the DTB
880 * If we are using dtb v2.0, then we have split board & msmdata in the DTB
881 */
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700882 board_data = (struct board_id *) malloc(sizeof(struct board_id) * (len_board_id / BOARD_ID_SIZE));
883 ASSERT(board_data);
884 platform_data = (struct plat_id *) malloc(sizeof(struct plat_id) * (len_plat_id / PLAT_ID_SIZE));
885 ASSERT(platform_data);
Lijuan Gao9f152862014-08-18 13:45:24 +0800886 if (dtb_ver == DEV_TREE_VERSION_V3) {
887 pmic_data = (struct pmic_id *) malloc(sizeof(struct pmic_id) * (len_pmic_id / PMIC_ID_SIZE));
888 ASSERT(pmic_data);
889 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700890 i = 0;
891
892 /* Extract board data from DTB */
Lijuan Gao9f152862014-08-18 13:45:24 +0800893 for(i = 0 ; i < board_data_count; i++) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700894 board_data[i].variant_id = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id);
895 board_data[i].platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->platform_subtype);
Lijuan Gao9f152862014-08-18 13:45:24 +0800896 /* For V2/V3 version of DTBs we have platform version field as part
897 * of variant ID, in such case the subtype will be mentioned as 0x0
898 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
899 * SS -- Subtype
900 * PM -- Platform major version
901 * Pm -- Platform minor version
902 * PH -- Platform hardware CDP/MTP
903 * In such case to make it compatible with LK algorithm move the subtype
904 * from variant_id to subtype field
905 */
906 if (board_data[i].platform_subtype == 0)
907 board_data[i].platform_subtype =
908 fdt32_to_cpu(((struct board_id *)board_prop)->variant_id) >> 0x18;
909
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700910 len_board_id -= sizeof(struct board_id);
911 board_prop += sizeof(struct board_id);
912 }
913
914 /* Extract platform data from DTB */
Lijuan Gao9f152862014-08-18 13:45:24 +0800915 for(i = 0 ; i < msm_data_count; i++) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700916 platform_data[i].platform_id = fdt32_to_cpu(((struct plat_id *)plat_prop)->platform_id);
917 platform_data[i].soc_rev = fdt32_to_cpu(((struct plat_id *)plat_prop)->soc_rev);
918 len_plat_id -= sizeof(struct plat_id);
919 plat_prop += sizeof(struct plat_id);
920 }
921
Lijuan Gao9f152862014-08-18 13:45:24 +0800922 if (dtb_ver == DEV_TREE_VERSION_V3 && pmic_prop) {
923 /* Extract pmic data from DTB */
924 for(i = 0 ; i < pmic_data_count; i++) {
925 pmic_data[i].pmic_version[0]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[0]);
926 pmic_data[i].pmic_version[1]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[1]);
927 pmic_data[i].pmic_version[2]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[2]);
928 pmic_data[i].pmic_version[3]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[3]);
929 len_pmic_id -= sizeof(struct pmic_id);
930 pmic_prop += sizeof(struct pmic_id);
931 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700932
Lijuan Gao9f152862014-08-18 13:45:24 +0800933 /* We need to merge board & platform data into dt entry structure */
934 num_entries = msm_data_count * board_data_count * pmic_data_count;
935 } else {
936 /* We need to merge board & platform data into dt entry structure */
937 num_entries = msm_data_count * board_data_count;
938 }
vijay kumar89d36d82014-06-30 19:32:18 +0530939
Lijuan Gao9f152862014-08-18 13:45:24 +0800940 if ((((uint64_t)msm_data_count * (uint64_t)board_data_count * (uint64_t)pmic_data_count) !=
941 msm_data_count * board_data_count * pmic_data_count) ||
942 (((uint64_t)msm_data_count * (uint64_t)board_data_count) != msm_data_count * board_data_count)) {
943
944 free(board_data);
945 free(platform_data);
946 if (pmic_data)
947 free(pmic_data);
948 if (model)
949 free(model);
950 return false;
951 }
952
953 dt_entry_array = (struct dt_entry*) malloc(sizeof(struct dt_entry) * num_entries);
954 ASSERT(dt_entry_array);
955
956 /* If we have '<X>; <Y>; <Z>' as platform data & '<A>; <B>; <C>' as board data.
957 * Then dt entry should look like
958 * <X ,A >;<X, B>;<X, C>;
959 * <Y ,A >;<Y, B>;<Y, C>;
960 * <Z ,A >;<Z, B>;<Z, C>;
961 */
962 i = 0;
963 k = 0;
964 n = 0;
965 for (i = 0; i < msm_data_count; i++) {
966 for (j = 0; j < board_data_count; j++) {
967 if (dtb_ver == DEV_TREE_VERSION_V3 && pmic_prop) {
968 for (n = 0; n < pmic_data_count; n++) {
969 dt_entry_array[k].platform_id = platform_data[i].platform_id;
970 dt_entry_array[k].soc_rev = platform_data[i].soc_rev;
971 dt_entry_array[k].variant_id = board_data[j].variant_id;
972 dt_entry_array[k].board_hw_subtype = board_data[j].platform_subtype;
973 dt_entry_array[k].pmic_rev[0]= pmic_data[n].pmic_version[0];
974 dt_entry_array[k].pmic_rev[1]= pmic_data[n].pmic_version[1];
975 dt_entry_array[k].pmic_rev[2]= pmic_data[n].pmic_version[2];
976 dt_entry_array[k].pmic_rev[3]= pmic_data[n].pmic_version[3];
977 dt_entry_array[k].offset = (uint32_t)dtb;
978 dt_entry_array[k].size = dtb_size;
979 k++;
980 }
981
982 } else {
983 dt_entry_array[k].platform_id = platform_data[i].platform_id;
984 dt_entry_array[k].soc_rev = platform_data[i].soc_rev;
985 dt_entry_array[k].variant_id = board_data[j].variant_id;
986 dt_entry_array[k].board_hw_subtype = board_data[j].platform_subtype;
987 dt_entry_array[k].pmic_rev[0]= board_pmic_target(0);
988 dt_entry_array[k].pmic_rev[1]= board_pmic_target(1);
989 dt_entry_array[k].pmic_rev[2]= board_pmic_target(2);
990 dt_entry_array[k].pmic_rev[3]= board_pmic_target(3);
991 dt_entry_array[k].offset = (uint32_t)dtb;
992 dt_entry_array[k].size = dtb_size;
vijay kumar89d36d82014-06-30 19:32:18 +0530993 k++;
994 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700995 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800996 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700997
Lijuan Gao9f152862014-08-18 13:45:24 +0800998 for (i=0 ;i < num_entries; i++) {
999 dprintf(SPEW, "Found an appended flattened device tree (%s - %u %u %u 0x%x)\n",
1000 *model ? model : "unknown",
1001 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 +05301002
Lijuan Gao9f152862014-08-18 13:45:24 +08001003 if (platform_dt_absolute_match(&(dt_entry_array[i]), dtb_list)) {
1004 dprintf(SPEW, "Device tree exact match the board: <%u %u %u 0x%x> == <%u %u %u 0x%x>\n",
1005 dt_entry_array[i].platform_id,
1006 dt_entry_array[i].variant_id,
1007 dt_entry_array[i].soc_rev,
1008 dt_entry_array[i].board_hw_subtype,
1009 board_platform_id(),
1010 board_hardware_id(),
1011 board_hardware_subtype(),
1012 board_soc_version());
vijay kumar89d36d82014-06-30 19:32:18 +05301013
Lijuan Gao9f152862014-08-18 13:45:24 +08001014 } else {
1015 dprintf(SPEW, "Device tree's msm_id doesn't match the board: <%u %u %u 0x%x> != <%u %u %u 0x%x>\n",
1016 dt_entry_array[i].platform_id,
1017 dt_entry_array[i].variant_id,
1018 dt_entry_array[i].soc_rev,
1019 dt_entry_array[i].board_hw_subtype,
1020 board_platform_id(),
1021 board_hardware_id(),
1022 board_hardware_subtype(),
1023 board_soc_version());
Channagoud Kadabia4dbe332013-09-05 17:44:11 -07001024 }
1025 }
Lijuan Gao9f152862014-08-18 13:45:24 +08001026
1027 free(board_data);
1028 free(platform_data);
1029 if (pmic_data)
1030 free(pmic_data);
1031 free(dt_entry_array);
Dima Zavinc46f8382013-05-03 12:23:06 -07001032 }
Lijuan Gao9f152862014-08-18 13:45:24 +08001033 if (model)
vijay kumar89d36d82014-06-30 19:32:18 +05301034 free(model);
Lijuan Gao9f152862014-08-18 13:45:24 +08001035 return true;
Dima Zavinc46f8382013-05-03 12:23:06 -07001036}
1037
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301038/* function to handle the overlay in independent thread */
1039static int dtb_overlay_handler(void *args)
1040{
1041 dprintf(SPEW, "thread %s() started\n", __func__);
1042
1043 soc_dtb_hdr = ufdt_install_blob(soc_dtb, fdt_totalsize(soc_dtb));
1044 if(!soc_dtb_hdr)
1045 {
1046 dprintf(CRITICAL, "ERROR: Install Blob failed\n");
1047 ret = DTBO_ERROR;
1048 goto out;
1049 }
1050 final_dtb_hdr = ufdt_apply_overlay(soc_dtb_hdr, fdt_totalsize(soc_dtb_hdr),board_dtb,
1051 fdt_totalsize(board_dtb));
1052 if (!final_dtb_hdr)
1053 {
1054 dprintf(CRITICAL, "ERROR: UFDT apply overlay failed\n");
1055 ret = DTBO_ERROR;
1056 goto out;
1057 }
1058out:
1059 /* This flag can only be updated here, hence it is not protected */
1060 event_signal(&dtbo_event, true);
1061 thread_exit(0);
1062 return 0;
1063}
1064
1065/*
1066 * Function to check and form new dtb with Overlay support.
1067*/
1068dtbo_error dev_tree_appended_with_dtbo(void *kernel, uint32_t kernel_size,
1069 uint32_t dtb_offset, void *tags)
1070{
1071 void *dtbo_image_buf = NULL;
Mayank Groverb61c0c22018-09-04 15:09:32 +05301072 uint32_t dtbo_image_sz = 0;
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301073
Mayank Grover302432a2017-12-08 17:18:58 +05301074 bs_set_timestamp(BS_DTB_OVERLAY_START);
Mayank Groverb61c0c22018-09-04 15:09:32 +05301075 ret = load_validate_dtbo_image(&dtbo_image_buf, &dtbo_image_sz);
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301076 if (ret == DTBO_SUCCESS)
1077 {
1078 final_dtb_hdr = soc_dtb = get_soc_dtb(kernel,
1079 kernel_size, dtb_offset);
1080 if(!soc_dtb)
1081 {
1082 ret = DTBO_ERROR;
1083 goto out;
1084 }
1085
1086 if (dtbo_needed)
1087 {
1088 board_dtb = get_board_dtb(dtbo_image_buf);
1089 if(!board_dtb)
1090 {
1091 ret = DTBO_ERROR;
1092 goto out;
1093 }
1094
1095 if((ADD_OF((fdt_totalsize(soc_dtb)), (fdt_totalsize(board_dtb)))) > MAX_DTBO_SZ)
1096 {
1097 dprintf(CRITICAL, "ERROR: dtb greater than max supported.\n");
1098 ret = DTBO_ERROR;
1099 goto out;
1100 }
1101
1102 /*
1103 spawn a seperate thread for dtbo overlay with indpendent,
1104 stack to avoid issues with stack corruption seen during flattening,
1105 of dtb in overlay functionality
1106 */
1107 {
1108 thread_t *thr = NULL;
1109 event_init(&dtbo_event, 0, EVENT_FLAG_AUTOUNSIGNAL);
1110 thr = thread_create("dtb_overlay", dtb_overlay_handler, 0,
1111 DEFAULT_PRIORITY, DTBO_STACK_SIZE);
1112 if (!thr)
1113 {
1114 dprintf(CRITICAL, "ERROR: Failed to create DTBO thread.\n");
1115 ret = DTBO_ERROR;
1116 goto out;
1117 }
1118 thread_resume(thr);
1119
1120 /* block current thread, untill woken up by dtb_overlay_handler. */
1121 event_wait(&dtbo_event);
1122
1123 /* ret is updated by dtb overlay thread, in case of error */
1124 if(ret == DTBO_ERROR)
1125 {
1126 goto out;
1127 }
1128 } /* dtbo_overlay_handler exited */
1129
1130 }
1131 memscpy(tags, fdt_totalsize(final_dtb_hdr), final_dtb_hdr,
1132 fdt_totalsize(final_dtb_hdr));
Mayank Grover71f63862018-05-03 17:06:41 +05301133 dprintf(INFO, "DTB overlay is successful\n");
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301134 }
1135 else
1136 {
Mayank Grover71f63862018-05-03 17:06:41 +05301137 dprintf(INFO, "ERROR: DTBO read is not valid\n DTB Overlay failed.\n");
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301138 ret = DTBO_NOT_SUPPORTED;
1139 }
1140out:
Mayank Grover302432a2017-12-08 17:18:58 +05301141 bs_set_timestamp(BS_DTB_OVERLAY_END);
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301142 return ret;
1143}
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001144/*
Dima Zavin77e41f32013-03-06 16:10:43 -08001145 * Will relocate the DTB to the tags addr if the device tree is found and return
1146 * its address
1147 *
1148 * Arguments: kernel - Start address of the kernel loaded in RAM
1149 * tags - Start address of the tags loaded in RAM
Channagoud Kadabi704cd562013-04-25 15:19:59 -07001150 * kernel_size - Size of the kernel in bytes
1151 *
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001152 * Return Value: DTB address : If appended device tree is found
Dima Zavin77e41f32013-03-06 16:10:43 -08001153 * 'NULL' : Otherwise
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001154 */
Matthew Qinbb7923d2015-02-09 10:56:09 +08001155void *dev_tree_appended(void *kernel, uint32_t kernel_size, uint32_t dtb_offset, void *tags)
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001156{
Parth Dixit97e47bb2016-03-07 17:20:44 +05301157 uintptr_t kernel_end = (uintptr_t)kernel + kernel_size;
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001158 uint32_t app_dtb_offset = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +08001159 void *dtb = NULL;
Shashank Mittalc0f10282013-07-15 14:53:31 -07001160 void *bestmatch_tag = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +08001161 struct dt_entry *best_match_dt_entry = NULL;
Shashank Mittalc0f10282013-07-15 14:53:31 -07001162 uint32_t bestmatch_tag_size;
Lijuan Gao9f152862014-08-18 13:45:24 +08001163 struct dt_entry_node *dt_entry_queue = NULL;
1164 struct dt_entry_node *dt_node_tmp1 = NULL;
1165 struct dt_entry_node *dt_node_tmp2 = NULL;
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301166 dtbo_error ret = DTBO_NOT_SUPPORTED;
1167
lijuangdc1b5422018-05-07 17:12:59 +08001168 if (dtb_offset)
1169 app_dtb_offset = dtb_offset;
1170 else
1171 memcpy((void*) &app_dtb_offset, (void*) (kernel + DTB_OFFSET), sizeof(uint32_t));
1172
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301173 /* Check for dtbo support */
lijuangdc1b5422018-05-07 17:12:59 +08001174 ret = dev_tree_appended_with_dtbo(kernel, kernel_size, app_dtb_offset, tags);
Mayank Grover1b6da5d2017-12-19 16:05:46 +05301175 if (ret == DTBO_SUCCESS)
1176 return tags;
1177 else if (ret == DTBO_ERROR)
1178 return NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +08001179
Lijuan Gao9f152862014-08-18 13:45:24 +08001180 /* Initialize the dtb entry node*/
1181 dt_entry_queue = (struct dt_entry_node *)
1182 malloc(sizeof(struct dt_entry_node));
1183
1184 if (!dt_entry_queue) {
1185 dprintf(CRITICAL, "Out of memory\n");
1186 return NULL;
1187 }
1188 list_initialize(&dt_entry_queue->node);
1189
vijay kumare2a5ea82014-06-25 12:24:14 +05301190 if (((uintptr_t)kernel + (uintptr_t)app_dtb_offset) < (uintptr_t)kernel) {
1191 return NULL;
1192 }
Parth Dixit97e47bb2016-03-07 17:20:44 +05301193 dtb = (void *)((uintptr_t)kernel + app_dtb_offset);
1194
vijay kumare2a5ea82014-06-25 12:24:14 +05301195 while (((uintptr_t)dtb + sizeof(struct fdt_header)) < (uintptr_t)kernel_end) {
Dima Zavinc46f8382013-05-03 12:23:06 -07001196 struct fdt_header dtb_hdr;
1197 uint32_t dtb_size;
Dima Zavin77e41f32013-03-06 16:10:43 -08001198
Dima Zavinc46f8382013-05-03 12:23:06 -07001199 /* the DTB could be unaligned, so extract the header,
1200 * and operate on it separately */
1201 memcpy(&dtb_hdr, dtb, sizeof(struct fdt_header));
1202 if (fdt_check_header((const void *)&dtb_hdr) != 0 ||
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +05301203 fdt_check_header_ext((const void *)&dtb_hdr) != 0 ||
vijay kumare2a5ea82014-06-25 12:24:14 +05301204 ((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) < (uintptr_t)dtb) ||
1205 ((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) > (uintptr_t)kernel_end))
Dima Zavinc46f8382013-05-03 12:23:06 -07001206 break;
1207 dtb_size = fdt_totalsize(&dtb_hdr);
1208
Lijuan Gao9f152862014-08-18 13:45:24 +08001209 dev_tree_compatible(dtb, dtb_size, dt_entry_queue);
Dima Zavinc46f8382013-05-03 12:23:06 -07001210
1211 /* goto the next device tree if any */
1212 dtb += dtb_size;
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001213 }
Dima Zavinc46f8382013-05-03 12:23:06 -07001214
Lijuan Gao9f152862014-08-18 13:45:24 +08001215 best_match_dt_entry = platform_dt_match_best(dt_entry_queue);
1216 if (best_match_dt_entry){
1217 bestmatch_tag = (void *)best_match_dt_entry->offset;
1218 bestmatch_tag_size = best_match_dt_entry->size;
1219 dprintf(INFO, "Best match DTB tags %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1220 best_match_dt_entry->platform_id, best_match_dt_entry->variant_id,
1221 best_match_dt_entry->board_hw_subtype, best_match_dt_entry->soc_rev,
1222 best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],
1223 best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],
1224 best_match_dt_entry->offset, best_match_dt_entry->size);
1225 dprintf(INFO, "Using pmic info 0x%0x/0x%x/0x%x/0x%0x for device 0x%0x/0x%x/0x%x/0x%0x\n",
1226 best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],
1227 best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],
1228 board_pmic_target(0), board_pmic_target(1),
1229 board_pmic_target(2), board_pmic_target(3));
1230 }
1231 /* free queue's memory */
1232 list_for_every_entry(&dt_entry_queue->node, dt_node_tmp1, dt_node, node) {
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001233 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001234 dt_entry_list_delete(dt_node_tmp1);
1235 dt_node_tmp1 = dt_node_tmp2;
1236 }
1237
Shashank Mittalc0f10282013-07-15 14:53:31 -07001238 if(bestmatch_tag) {
Parth Dixitc2f0cb92016-03-10 10:40:14 +05301239 if (check_aboot_addr_range_overlap((uintptr_t)tags, bestmatch_tag_size)) {
1240 dprintf(CRITICAL, "Tags addresses overlap with aboot addresses.\n");
1241 return NULL;
1242 }
Shashank Mittalc0f10282013-07-15 14:53:31 -07001243 memcpy(tags, bestmatch_tag, bestmatch_tag_size);
1244 /* clear out the old DTB magic so kernel doesn't find it */
1245 *((uint32_t *)(kernel + app_dtb_offset)) = 0;
1246 return tags;
1247 }
1248
Dima Zavinc46f8382013-05-03 12:23:06 -07001249 dprintf(CRITICAL, "DTB offset is incorrect, kernel image does not have appended DTB\n");
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001250
David Ng59c4a782015-05-14 15:51:44 -07001251 dprintf(INFO, "Device info 0x%08x/%08x/0x%08x/%u, pmic 0x%0x/0x%x/0x%x/0x%0x\n",
1252 board_platform_id(), board_soc_version(),
1253 board_target_id(), board_hardware_subtype(),
1254 board_pmic_target(0), board_pmic_target(1),
1255 board_pmic_target(2), board_pmic_target(3));
Dima Zavin77e41f32013-03-06 16:10:43 -08001256 return NULL;
Channagoud Kadabi11682e92013-02-28 11:21:46 -08001257}
1258
Joel Kingaa335dc2013-06-03 16:11:08 -07001259/* Returns 0 if the device tree is valid. */
Deepa Dinamani87252952013-09-09 13:58:27 -07001260int dev_tree_validate(struct dt_table *table, unsigned int page_size, uint32_t *dt_hdr_size)
Joel Kingaa335dc2013-06-03 16:11:08 -07001261{
1262 int dt_entry_size;
Channagoud Kadabid87c2772014-06-20 15:41:55 -07001263 uint64_t hdr_size;
Joel Kingaa335dc2013-06-03 16:11:08 -07001264
1265 /* Validate the device tree table header */
1266 if(table->magic != DEV_TREE_MAGIC) {
1267 dprintf(CRITICAL, "ERROR: Bad magic in device tree table \n");
1268 return -1;
1269 }
1270
1271 if (table->version == DEV_TREE_VERSION_V1) {
1272 dt_entry_size = sizeof(struct dt_entry_v1);
1273 } else if (table->version == DEV_TREE_VERSION_V2) {
Lijuan Gao9f152862014-08-18 13:45:24 +08001274 dt_entry_size = sizeof(struct dt_entry_v2);
1275 } else if (table->version == DEV_TREE_VERSION_V3) {
Joel Kingaa335dc2013-06-03 16:11:08 -07001276 dt_entry_size = sizeof(struct dt_entry);
1277 } else {
1278 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
1279 table->version);
1280 return -1;
1281 }
1282
Channagoud Kadabid87c2772014-06-20 15:41:55 -07001283 hdr_size = (uint64_t)table->num_entries * dt_entry_size + DEV_TREE_HEADER_SIZE;
1284
Deepa Dinamani87252952013-09-09 13:58:27 -07001285 /* Roundup to page_size. */
1286 hdr_size = ROUNDUP(hdr_size, page_size);
1287
Channagoud Kadabid87c2772014-06-20 15:41:55 -07001288 if (hdr_size > UINT_MAX)
1289 return -1;
1290 else
1291 *dt_hdr_size = hdr_size & UINT_MAX;
Joel Kingaa335dc2013-06-03 16:11:08 -07001292
1293 return 0;
1294}
1295
Lijuan Gao9f152862014-08-18 13:45:24 +08001296static int platform_dt_absolute_match(struct dt_entry *cur_dt_entry, struct dt_entry_node *dt_list)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001297{
Lijuan Gaof8e95722014-12-23 03:03:12 -05001298 uint32_t cur_dt_hlos_ddr;
Lijuan Gao9f152862014-08-18 13:45:24 +08001299 uint32_t cur_dt_hw_platform;
1300 uint32_t cur_dt_hw_subtype;
1301 uint32_t cur_dt_msm_id;
1302 dt_node *dt_node_tmp = NULL;
Channagoud Kadabi571193a2014-02-05 13:58:49 -08001303
Lijuan Gao9f152862014-08-18 13:45:24 +08001304 /* Platform-id
1305 * bit no |31 24|23 16|15 0|
1306 * |reserved|foundry-id|msm-id|
1307 */
1308 cur_dt_msm_id = (cur_dt_entry->platform_id & 0x0000ffff);
1309 cur_dt_hw_platform = (cur_dt_entry->variant_id & 0x000000ff);
Lijuan Gao0621b862014-09-02 10:02:52 +08001310 cur_dt_hw_subtype = (cur_dt_entry->board_hw_subtype & 0xff);
Lijuan Gao9f152862014-08-18 13:45:24 +08001311
Lijuan Gaof8e95722014-12-23 03:03:12 -05001312 /* Determine the bits 10:8 to check the DT with the DDR Size */
1313 cur_dt_hlos_ddr = (cur_dt_entry->board_hw_subtype & 0x700);
Channagoud Kadabi571193a2014-02-05 13:58:49 -08001314
Lijuan Gao9f152862014-08-18 13:45:24 +08001315 /* 1. must match the msm_id, platform_hw_id, platform_subtype and DDR size
1316 * soc, board major/minor, pmic major/minor must less than board info
1317 * 2. find the matched DTB then return 1
1318 * 3. otherwise return 0
Maria Yu2e2d2c22013-07-03 19:20:33 +08001319 */
Lijuan Gao9f152862014-08-18 13:45:24 +08001320 if((cur_dt_msm_id == (board_platform_id() & 0x0000ffff)) &&
1321 (cur_dt_hw_platform == board_hardware_id()) &&
1322 (cur_dt_hw_subtype == board_hardware_subtype()) &&
Lijuan Gaof8e95722014-12-23 03:03:12 -05001323 (cur_dt_hlos_ddr == (target_get_hlos_subtype() & 0x700)) &&
Lijuan Gao9f152862014-08-18 13:45:24 +08001324 (cur_dt_entry->soc_rev <= board_soc_version()) &&
1325 ((cur_dt_entry->variant_id & 0x00ffff00) <= (board_target_id() & 0x00ffff00)) &&
1326 ((cur_dt_entry->pmic_rev[0] & 0x00ffff00) <= (board_pmic_target(0) & 0x00ffff00)) &&
1327 ((cur_dt_entry->pmic_rev[1] & 0x00ffff00) <= (board_pmic_target(1) & 0x00ffff00)) &&
1328 ((cur_dt_entry->pmic_rev[2] & 0x00ffff00) <= (board_pmic_target(2) & 0x00ffff00)) &&
1329 ((cur_dt_entry->pmic_rev[3] & 0x00ffff00) <= (board_pmic_target(3) & 0x00ffff00))) {
Maria Yu2e2d2c22013-07-03 19:20:33 +08001330
Lijuan Gao9f152862014-08-18 13:45:24 +08001331 dt_node_tmp = dt_entry_list_init();
1332 memcpy((char*)dt_node_tmp->dt_entry_m,(char*)cur_dt_entry, sizeof(struct dt_entry));
1333
1334 dprintf(SPEW, "Add DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1335 dt_node_tmp->dt_entry_m->platform_id, dt_node_tmp->dt_entry_m->variant_id,
1336 dt_node_tmp->dt_entry_m->board_hw_subtype, dt_node_tmp->dt_entry_m->soc_rev,
1337 dt_node_tmp->dt_entry_m->pmic_rev[0], dt_node_tmp->dt_entry_m->pmic_rev[1],
1338 dt_node_tmp->dt_entry_m->pmic_rev[2], dt_node_tmp->dt_entry_m->pmic_rev[3],
1339 dt_node_tmp->dt_entry_m->offset, dt_node_tmp->dt_entry_m->size);
1340
1341 insert_dt_entry_in_queue(dt_list, dt_node_tmp);
1342 return 1;
1343 }
1344 return 0;
1345}
1346
1347static int platform_dt_absolute_compat_match(struct dt_entry_node *dt_list, uint32_t dtb_info) {
1348 struct dt_entry_node *dt_node_tmp1 = NULL;
1349 struct dt_entry_node *dt_node_tmp2 = NULL;
1350 uint32_t current_info = 0;
1351 uint32_t board_info = 0;
1352 uint32_t best_info = 0;
1353 uint32_t current_pmic_model[4] = {0, 0, 0, 0};
1354 uint32_t board_pmic_model[4] = {0, 0, 0, 0};
1355 uint32_t best_pmic_model[4] = {0, 0, 0, 0};
1356 uint32_t delete_current_dt = 0;
1357 uint32_t i;
1358
1359 /* start to select the exact entry
1360 * default to exact match 0, if find current DTB entry info is the same as board info,
1361 * then exact match board info.
1362 */
1363 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1364 if (!dt_node_tmp1){
1365 dprintf(SPEW, "Current node is the end\n");
1366 break;
1367 }
1368 switch(dtb_info) {
1369 case DTB_FOUNDRY:
1370 current_info = ((dt_node_tmp1->dt_entry_m->platform_id) & 0x00ff0000);
Channagoud Kadabi4cffc272014-10-29 11:23:26 -07001371 board_info = board_foundry_id() << 16;
Lijuan Gao9f152862014-08-18 13:45:24 +08001372 break;
1373 case DTB_PMIC_MODEL:
1374 for (i = 0; i < 4; i++) {
1375 current_pmic_model[i] = (dt_node_tmp1->dt_entry_m->pmic_rev[i] & 0xff);
1376 board_pmic_model[i] = (board_pmic_target(i) & 0xff);
1377 }
1378 break;
Lijuan Gaof8e95722014-12-23 03:03:12 -05001379 case DTB_PANEL_TYPE:
1380 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0x1800);
1381 board_info = (target_get_hlos_subtype() & 0x1800);
1382 break;
1383 case DTB_BOOT_DEVICE:
1384 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0xf0000);
1385 board_info = (target_get_hlos_subtype() & 0xf0000);
1386 break;
Lijuan Gao9f152862014-08-18 13:45:24 +08001387 default:
1388 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
1389 dtb_info);
Maria Yuca51ee22013-06-27 21:45:24 +08001390 return 0;
Lijuan Gao9f152862014-08-18 13:45:24 +08001391 }
1392
1393 if (dtb_info == DTB_PMIC_MODEL) {
1394 if ((current_pmic_model[0] == board_pmic_model[0]) &&
1395 (current_pmic_model[1] == board_pmic_model[1]) &&
1396 (current_pmic_model[2] == board_pmic_model[2]) &&
1397 (current_pmic_model[3] == board_pmic_model[3])) {
1398
1399 for (i = 0; i < 4; i++) {
1400 best_pmic_model[i] = current_pmic_model[i];
1401 }
1402 break;
1403 }
1404 } else {
1405 if (current_info == board_info) {
1406 best_info = current_info;
1407 break;
1408 }
1409 }
1410 }
1411
1412 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1413 if (!dt_node_tmp1){
1414 dprintf(SPEW, "Current node is the end\n");
1415 break;
1416 }
1417 switch(dtb_info) {
1418 case DTB_FOUNDRY:
1419 current_info = ((dt_node_tmp1->dt_entry_m->platform_id) & 0x00ff0000);
1420 break;
1421 case DTB_PMIC_MODEL:
1422 for (i = 0; i < 4; i++) {
1423 current_pmic_model[i] = (dt_node_tmp1->dt_entry_m->pmic_rev[i] & 0xff);
1424 }
1425 break;
Lijuan Gaof8e95722014-12-23 03:03:12 -05001426 case DTB_PANEL_TYPE:
1427 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0x1800);
1428 break;
1429 case DTB_BOOT_DEVICE:
1430 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0xf0000);
1431 break;
Lijuan Gao9f152862014-08-18 13:45:24 +08001432 default:
1433 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
1434 dtb_info);
1435 return 0;
1436 }
1437
1438 if (dtb_info == DTB_PMIC_MODEL) {
1439 if ((current_pmic_model[0] != best_pmic_model[0]) ||
1440 (current_pmic_model[1] != best_pmic_model[1]) ||
1441 (current_pmic_model[2] != best_pmic_model[2]) ||
1442 (current_pmic_model[3] != best_pmic_model[3])) {
1443
1444 delete_current_dt = 1;
1445 }
1446 } else {
1447 if (current_info != best_info) {
1448 delete_current_dt = 1;
1449 }
1450 }
1451
1452 if (delete_current_dt) {
1453 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1454 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
1455 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
1456 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
1457 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
1458 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
1459
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001460 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001461 dt_entry_list_delete(dt_node_tmp1);
1462 dt_node_tmp1 = dt_node_tmp2;
1463 delete_current_dt = 0;
Maria Yuca51ee22013-06-27 21:45:24 +08001464 }
1465 }
Maria Yuca51ee22013-06-27 21:45:24 +08001466
Maria Yu2e2d2c22013-07-03 19:20:33 +08001467 return 1;
Maria Yuca51ee22013-06-27 21:45:24 +08001468}
1469
Lijuan Gao9f152862014-08-18 13:45:24 +08001470static int update_dtb_entry_node(struct dt_entry_node *dt_list, uint32_t dtb_info) {
1471 struct dt_entry_node *dt_node_tmp1 = NULL;
1472 struct dt_entry_node *dt_node_tmp2 = NULL;
1473 uint32_t current_info = 0;
1474 uint32_t board_info = 0;
1475 uint32_t best_info = 0;
1476
1477 /* start to select the best entry*/
1478 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1479 if (!dt_node_tmp1){
1480 dprintf(SPEW, "Current node is the end\n");
1481 break;
1482 }
1483 switch(dtb_info) {
1484 case DTB_SOC:
1485 current_info = dt_node_tmp1->dt_entry_m->soc_rev;
1486 board_info = board_soc_version();
1487 break;
1488 case DTB_MAJOR_MINOR:
1489 current_info = ((dt_node_tmp1->dt_entry_m->variant_id) & 0x00ffff00);
1490 board_info = (board_target_id() & 0x00ffff00);
1491 break;
1492 case DTB_PMIC0:
1493 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[0]) & 0x00ffff00);
1494 board_info = (board_pmic_target(0) & 0x00ffff00);
1495 break;
1496 case DTB_PMIC1:
1497 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[1]) & 0x00ffff00);
1498 board_info = (board_pmic_target(1) & 0x00ffff00);
1499 break;
1500 case DTB_PMIC2:
1501 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[2]) & 0x00ffff00);
1502 board_info = (board_pmic_target(2) & 0x00ffff00);
1503 break;
1504 case DTB_PMIC3:
1505 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[3]) & 0x00ffff00);
1506 board_info = (board_pmic_target(3) & 0x00ffff00);
1507 break;
1508 default:
1509 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
1510 dtb_info);
1511 return 0;
1512 }
1513
1514 if (current_info == board_info) {
1515 best_info = current_info;
1516 break;
1517 }
1518 if ((current_info < board_info) && (current_info > best_info)) {
1519 best_info = current_info;
1520 }
1521 if (current_info < best_info) {
1522 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1523 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
1524 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
1525 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
1526 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
1527 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
1528
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001529 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001530 dt_entry_list_delete(dt_node_tmp1);
1531 dt_node_tmp1 = dt_node_tmp2;
1532 }
1533 }
1534
1535 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1536 if (!dt_node_tmp1){
1537 dprintf(SPEW, "Current node is the end\n");
1538 break;
1539 }
1540 switch(dtb_info) {
1541 case DTB_SOC:
1542 current_info = dt_node_tmp1->dt_entry_m->soc_rev;
1543 break;
1544 case DTB_MAJOR_MINOR:
1545 current_info = ((dt_node_tmp1->dt_entry_m->variant_id) & 0x00ffff00);
1546 break;
1547 case DTB_PMIC0:
1548 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[0]) & 0x00ffff00);
1549 break;
1550 case DTB_PMIC1:
1551 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[1]) & 0x00ffff00);
1552 break;
1553 case DTB_PMIC2:
1554 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[2]) & 0x00ffff00);
1555 break;
1556 case DTB_PMIC3:
1557 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[3]) & 0x00ffff00);
1558 break;
1559 default:
1560 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
1561 dtb_info);
1562 return 0;
1563 }
1564
1565 if (current_info != best_info) {
1566 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
1567 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
1568 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
1569 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
1570 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
1571 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
1572
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001573 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001574 dt_entry_list_delete(dt_node_tmp1);
1575 dt_node_tmp1 = dt_node_tmp2;
1576 }
1577 }
1578 return 1;
1579}
1580
1581static struct dt_entry *platform_dt_match_best(struct dt_entry_node *dt_list)
1582{
1583 struct dt_entry_node *dt_node_tmp1 = NULL;
1584
1585 /* check Foundry id
1586 * the foundry id must exact match board founddry id, this is compatibility check,
1587 * if couldn't find the exact match from DTB, will exact match 0x0.
1588 */
1589 if (!platform_dt_absolute_compat_match(dt_list, DTB_FOUNDRY))
1590 return NULL;
1591
1592 /* check PMIC model
1593 * the PMIC model must exact match board PMIC model, this is compatibility check,
1594 * if couldn't find the exact match from DTB, will exact match 0x0.
1595 */
1596 if (!platform_dt_absolute_compat_match(dt_list, DTB_PMIC_MODEL))
1597 return NULL;
1598
Lijuan Gaof8e95722014-12-23 03:03:12 -05001599 /* check panel type
1600 * the panel type must exact match board panel type, this is compatibility check,
1601 * if couldn't find the exact match from DTB, will exact match 0x0.
1602 */
1603 if (!platform_dt_absolute_compat_match(dt_list, DTB_PANEL_TYPE))
1604 return NULL;
1605
1606 /* check boot device subtype
1607 * the boot device subtype must exact match board boot device subtype, this is compatibility check,
1608 * if couldn't find the exact match from DTB, will exact match 0x0.
1609 */
1610 if (!platform_dt_absolute_compat_match(dt_list, DTB_BOOT_DEVICE))
1611 return NULL;
1612
Lijuan Gao9f152862014-08-18 13:45:24 +08001613 /* check soc version
1614 * the suitable soc version must less than or equal to board soc version
1615 */
1616 if (!update_dtb_entry_node(dt_list, DTB_SOC))
1617 return NULL;
1618
1619 /*check major and minor version
1620 * the suitable major&minor version must less than or equal to board major&minor version
1621 */
1622 if (!update_dtb_entry_node(dt_list, DTB_MAJOR_MINOR))
1623 return NULL;
1624
1625 /*check pmic info
1626 * the suitable pmic major&minor info must less than or equal to board pmic major&minor version
1627 */
1628 if (!update_dtb_entry_node(dt_list, DTB_PMIC0))
1629 return NULL;
1630 if (!update_dtb_entry_node(dt_list, DTB_PMIC1))
1631 return NULL;
1632 if (!update_dtb_entry_node(dt_list, DTB_PMIC2))
1633 return NULL;
1634 if (!update_dtb_entry_node(dt_list, DTB_PMIC3))
1635 return NULL;
1636
1637 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
1638 if (!dt_node_tmp1) {
1639 dprintf(CRITICAL, "ERROR: Couldn't find the suitable DTB!\n");
1640 return NULL;
1641 }
1642 if (dt_node_tmp1->dt_entry_m)
1643 return dt_node_tmp1->dt_entry_m;
1644 }
1645
1646 return NULL;
1647}
1648
1649/* Function to obtain the index information for the correct device tree
1650 * based on the platform data.
1651 * If a matching device tree is found, the information is returned in the
1652 * "dt_entry_info" out parameter and a function value of 0 is returned, otherwise
1653 * a non-zero function value is returned.
1654 */
1655int dev_tree_get_entry_info(struct dt_table *table, struct dt_entry *dt_entry_info)
Maria Yuca51ee22013-06-27 21:45:24 +08001656{
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001657 uint32_t i;
Lijuan Gao9f152862014-08-18 13:45:24 +08001658 unsigned char *table_ptr = NULL;
Joel Kingaa335dc2013-06-03 16:11:08 -07001659 struct dt_entry dt_entry_buf_1;
Lijuan Gao9f152862014-08-18 13:45:24 +08001660 struct dt_entry *cur_dt_entry = NULL;
1661 struct dt_entry *best_match_dt_entry = NULL;
1662 struct dt_entry_v1 *dt_entry_v1 = NULL;
1663 struct dt_entry_v2 *dt_entry_v2 = NULL;
1664 struct dt_entry_node *dt_entry_queue = NULL;
1665 struct dt_entry_node *dt_node_tmp1 = NULL;
1666 struct dt_entry_node *dt_node_tmp2 = NULL;
Maria Yu2e2d2c22013-07-03 19:20:33 +08001667 uint32_t found = 0;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001668
Joel Kingaa335dc2013-06-03 16:11:08 -07001669 if (!dt_entry_info) {
1670 dprintf(CRITICAL, "ERROR: Bad parameter passed to %s \n",
1671 __func__);
1672 return -1;
1673 }
1674
1675 table_ptr = (unsigned char *)table + DEV_TREE_HEADER_SIZE;
1676 cur_dt_entry = &dt_entry_buf_1;
1677 best_match_dt_entry = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +08001678 dt_entry_queue = (struct dt_entry_node *)
1679 malloc(sizeof(struct dt_entry_node));
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001680
Lijuan Gao9f152862014-08-18 13:45:24 +08001681 if (!dt_entry_queue) {
1682 dprintf(CRITICAL, "Out of memory\n");
1683 return -1;
1684 }
1685
1686 list_initialize(&dt_entry_queue->node);
1687 dprintf(INFO, "DTB Total entry: %d, DTB version: %d\n", table->num_entries, table->version);
Maria Yu2e2d2c22013-07-03 19:20:33 +08001688 for(i = 0; found == 0 && i < table->num_entries; i++)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001689 {
Joel Kingaa335dc2013-06-03 16:11:08 -07001690 memset(cur_dt_entry, 0, sizeof(struct dt_entry));
1691 switch(table->version) {
1692 case DEV_TREE_VERSION_V1:
1693 dt_entry_v1 = (struct dt_entry_v1 *)table_ptr;
1694 cur_dt_entry->platform_id = dt_entry_v1->platform_id;
1695 cur_dt_entry->variant_id = dt_entry_v1->variant_id;
1696 cur_dt_entry->soc_rev = dt_entry_v1->soc_rev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001697 cur_dt_entry->board_hw_subtype = (dt_entry_v1->variant_id >> 0x18);
1698 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
1699 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
1700 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
1701 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
Joel Kingaa335dc2013-06-03 16:11:08 -07001702 cur_dt_entry->offset = dt_entry_v1->offset;
1703 cur_dt_entry->size = dt_entry_v1->size;
1704 table_ptr += sizeof(struct dt_entry_v1);
1705 break;
1706 case DEV_TREE_VERSION_V2:
Lijuan Gao9f152862014-08-18 13:45:24 +08001707 dt_entry_v2 = (struct dt_entry_v2*)table_ptr;
1708 cur_dt_entry->platform_id = dt_entry_v2->platform_id;
1709 cur_dt_entry->variant_id = dt_entry_v2->variant_id;
1710 cur_dt_entry->soc_rev = dt_entry_v2->soc_rev;
1711 /* For V2 version of DTBs we have platform version field as part
1712 * of variant ID, in such case the subtype will be mentioned as 0x0
1713 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
1714 * SS -- Subtype
1715 * PM -- Platform major version
1716 * Pm -- Platform minor version
1717 * PH -- Platform hardware CDP/MTP
1718 * In such case to make it compatible with LK algorithm move the subtype
1719 * from variant_id to subtype field
1720 */
1721 if (dt_entry_v2->board_hw_subtype == 0)
1722 cur_dt_entry->board_hw_subtype = (cur_dt_entry->variant_id >> 0x18);
1723 else
1724 cur_dt_entry->board_hw_subtype = dt_entry_v2->board_hw_subtype;
1725 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
1726 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
1727 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
1728 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
1729 cur_dt_entry->offset = dt_entry_v2->offset;
1730 cur_dt_entry->size = dt_entry_v2->size;
1731 table_ptr += sizeof(struct dt_entry_v2);
1732 break;
1733 case DEV_TREE_VERSION_V3:
Joel Kingaa335dc2013-06-03 16:11:08 -07001734 memcpy(cur_dt_entry, (struct dt_entry *)table_ptr,
1735 sizeof(struct dt_entry));
Lijuan Gao9f152862014-08-18 13:45:24 +08001736 /* For V3 version of DTBs we have platform version field as part
1737 * of variant ID, in such case the subtype will be mentioned as 0x0
1738 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
1739 * SS -- Subtype
1740 * PM -- Platform major version
1741 * Pm -- Platform minor version
1742 * PH -- Platform hardware CDP/MTP
1743 * In such case to make it compatible with LK algorithm move the subtype
1744 * from variant_id to subtype field
1745 */
1746 if (cur_dt_entry->board_hw_subtype == 0)
1747 cur_dt_entry->board_hw_subtype = (cur_dt_entry->variant_id >> 0x18);
1748
Joel Kingaa335dc2013-06-03 16:11:08 -07001749 table_ptr += sizeof(struct dt_entry);
1750 break;
1751 default:
1752 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
1753 table->version);
Lijuan Gao9f152862014-08-18 13:45:24 +08001754 free(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001755 return -1;
1756 }
1757
Lijuan Gao9f152862014-08-18 13:45:24 +08001758 /* DTBs must match the platform_id, platform_hw_id, platform_subtype and DDR size.
1759 * The satisfactory DTBs are stored in dt_entry_queue
1760 */
1761 platform_dt_absolute_match(cur_dt_entry, dt_entry_queue);
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -08001762
Lijuan Gao9f152862014-08-18 13:45:24 +08001763 }
1764 best_match_dt_entry = platform_dt_match_best(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001765 if (best_match_dt_entry) {
1766 *dt_entry_info = *best_match_dt_entry;
Maria Yu2e2d2c22013-07-03 19:20:33 +08001767 found = 1;
1768 }
1769
1770 if (found != 0) {
Sundarajan Srinivasan763c0db2014-05-20 17:08:36 -07001771 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 -07001772 dt_entry_info->platform_id, dt_entry_info->soc_rev,
1773 dt_entry_info->variant_id, dt_entry_info->board_hw_subtype,
Lijuan Gao9f152862014-08-18 13:45:24 +08001774 board_platform_id(), board_soc_version(),
1775 board_target_id(), board_hardware_subtype());
1776 if (dt_entry_info->pmic_rev[0] == 0 && dt_entry_info->pmic_rev[0] == 0 &&
1777 dt_entry_info->pmic_rev[0] == 0 && dt_entry_info->pmic_rev[0] == 0) {
1778 dprintf(SPEW, "No maintain pmic info in DTB, device pmic info is 0x%0x/0x%x/0x%x/0x%0x\n",
1779 board_pmic_target(0), board_pmic_target(1),
1780 board_pmic_target(2), board_pmic_target(3));
1781 } else {
1782 dprintf(INFO, "Using pmic info 0x%0x/0x%x/0x%x/0x%0x for device 0x%0x/0x%x/0x%x/0x%0x\n",
1783 dt_entry_info->pmic_rev[0], dt_entry_info->pmic_rev[1],
1784 dt_entry_info->pmic_rev[2], dt_entry_info->pmic_rev[3],
1785 board_pmic_target(0), board_pmic_target(1),
1786 board_pmic_target(2), board_pmic_target(3));
1787 }
Joel Kingaa335dc2013-06-03 16:11:08 -07001788 return 0;
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -08001789 }
1790
Lijuan Gao9f152862014-08-18 13:45:24 +08001791 dprintf(CRITICAL, "ERROR: Unable to find suitable device tree for device (%u/0x%08x/0x%08x/%u)\n",
1792 board_platform_id(), board_soc_version(),
1793 board_target_id(), board_hardware_subtype());
1794
1795 list_for_every_entry(&dt_entry_queue->node, dt_node_tmp1, dt_node, node) {
1796 /* free node memory */
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001797 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001798 dt_entry_list_delete(dt_node_tmp1);
1799 dt_node_tmp1 = dt_node_tmp2;
1800 }
1801 free(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001802 return -1;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001803}
1804
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001805/* Function to add the first RAM partition info to the device tree.
1806 * Note: The function replaces the reg property in the "/memory" node
1807 * with the addr and size provided.
1808 */
1809int dev_tree_add_first_mem_info(uint32_t *fdt, uint32_t offset, uint32_t addr, uint32_t size)
1810{
1811 int ret;
1812
1813 ret = fdt_setprop_u32(fdt, offset, "reg", addr);
1814
1815 if (ret)
1816 {
1817 dprintf(CRITICAL, "Failed to add the memory information addr: %d\n",
1818 ret);
1819 }
1820
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001821 ret = fdt_appendprop_u32(fdt, offset, "reg", size);
1822
1823 if (ret)
1824 {
1825 dprintf(CRITICAL, "Failed to add the memory information size: %d\n",
1826 ret);
1827 }
1828
1829 return ret;
1830}
1831
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001832static 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 -07001833{
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001834 int len;
1835 uint32_t *valp;
1836 int ret;
1837 uint32_t offset;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001838
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001839 mem_node->offset = mem_node_offset;
1840
1841 /* Get offset of the root node */
1842 ret = fdt_path_offset(fdt, "/");
1843 if (ret < 0)
1844 {
1845 dprintf(CRITICAL, "Could not find memory node.\n");
1846 return ret;
1847 }
1848
1849 offset = ret;
1850
1851 /* Find the #address-cells size. */
1852 valp = (uint32_t*)fdt_getprop(fdt, offset, "#address-cells", &len);
Lijuan Gaoae0927b2014-07-18 17:16:16 +08001853 if (len <= 0 || !valp)
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001854 {
1855 if (len == -FDT_ERR_NOTFOUND)
1856 {
1857 /* Property not found.
1858 * Assume standard sizes.
1859 */
1860 mem_node->addr_cell_size = 2;
1861 dprintf(CRITICAL, "Using default #addr_cell_size: %u\n", mem_node->addr_cell_size);
1862 }
1863 else
1864 {
1865 dprintf(CRITICAL, "Error finding the #address-cells property\n");
1866 return len;
1867 }
1868 }
1869 else
1870 mem_node->addr_cell_size = fdt32_to_cpu(*valp);
1871
1872 /* Find the #size-cells size. */
1873 valp = (uint32_t*)fdt_getprop(fdt, offset, "#size-cells", &len);
Lijuan Gaoae0927b2014-07-18 17:16:16 +08001874 if (len <= 0 || !valp)
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001875 {
1876 if (len == -FDT_ERR_NOTFOUND)
1877 {
1878 /* Property not found.
1879 * Assume standard sizes.
1880 */
1881 mem_node->size_cell_size = 1;
1882 dprintf(CRITICAL, "Using default #size_cell_size: %u\n", mem_node->size_cell_size);
1883 }
1884 else
1885 {
1886 dprintf(CRITICAL, "Error finding the #size-cells property\n");
1887 return len;
1888 }
1889 }
1890 else
1891 mem_node->size_cell_size = fdt32_to_cpu(*valp);
1892
1893 return 0;
1894}
1895
1896static void dev_tree_update_memory_node(uint32_t offset)
1897{
1898 mem_node.offset = offset;
1899 mem_node.addr_cell_size = 1;
1900 mem_node.size_cell_size = 1;
1901}
1902
1903/* Function to add the subsequent RAM partition info to the device tree. */
1904int dev_tree_add_mem_info(void *fdt, uint32_t offset, uint64_t addr, uint64_t size)
1905{
1906 int ret = 0;
1907
1908 if(smem_get_ram_ptable_version() >= 1)
1909 {
1910 ret = dev_tree_query_memory_cell_sizes(fdt, &mem_node, offset);
1911 if (ret < 0)
1912 {
1913 dprintf(CRITICAL, "Could not find #address-cells and #size-cells properties: ret %d\n", ret);
1914 return ret;
1915 }
1916
1917 }
1918 else
1919 {
1920 dev_tree_update_memory_node(offset);
1921 }
1922
1923 if (!(mem_node.mem_info_cnt))
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001924 {
1925 /* Replace any other reg prop in the memory node. */
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001926
1927 /* cell_size is the number of 32 bit words used to represent an address/length in the device tree.
1928 * memory node in DT can be either 32-bit(cell-size = 1) or 64-bit(cell-size = 2).So when updating
1929 * the memory node in the device tree, we write one word or two words based on cell_size = 1 or 2.
1930 */
1931
1932 if(mem_node.addr_cell_size == 2)
1933 {
1934 ret = fdt_setprop_u32(fdt, mem_node.offset, "reg", addr >> 32);
1935 if(ret)
1936 {
1937 dprintf(CRITICAL, "ERROR: Could not set prop reg for memory node\n");
1938 return ret;
1939 }
1940
1941 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1942 if(ret)
1943 {
1944 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1945 return ret;
1946 }
1947 }
1948 else
1949 {
1950 ret = fdt_setprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1951 if(ret)
1952 {
1953 dprintf(CRITICAL, "ERROR: Could not set prop reg for memory node\n");
1954 return ret;
1955 }
1956 }
1957
1958 mem_node.mem_info_cnt = 1;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001959 }
1960 else
1961 {
1962 /* Append the mem info to the reg prop for subsequent nodes. */
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001963 if(mem_node.addr_cell_size == 2)
1964 {
1965 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", addr >> 32);
1966 if(ret)
1967 {
1968 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1969 return ret;
1970 }
1971 }
1972
1973 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1974 if(ret)
1975 {
1976 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1977 return ret;
1978 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001979 }
1980
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001981 if(mem_node.size_cell_size == 2)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001982 {
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001983 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", size>>32);
1984 if(ret)
1985 {
1986 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1987 return ret;
1988 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001989 }
1990
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001991 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)size);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001992
1993 if (ret)
1994 {
1995 dprintf(CRITICAL, "Failed to add the memory information size: %d\n",
1996 ret);
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001997 return ret;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001998 }
1999
2000 return ret;
2001}
2002
2003/* Top level function that updates the device tree. */
2004int update_device_tree(void *fdt, const char *cmdline,
2005 void *ramdisk, uint32_t ramdisk_size)
2006{
2007 int ret = 0;
2008 uint32_t offset;
lijuangc76a7632017-12-07 14:37:56 +08002009#if ENABLE_KASLRSEED_SUPPORT
lijuang0ac31232018-10-19 17:53:36 +08002010 uint64_t kaslrseed;
lijuangc76a7632017-12-07 14:37:56 +08002011#endif
Mayank Grover2533aab2018-02-23 18:06:07 +05302012 uint32_t cmdline_len = 0;
2013
2014 if (cmdline)
2015 cmdline_len = strlen(cmdline);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002016
2017 /* Check the device tree header */
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +05302018 ret = fdt_check_header(fdt) || fdt_check_header_ext(fdt);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002019 if (ret)
2020 {
2021 dprintf(CRITICAL, "Invalid device tree header \n");
2022 return ret;
2023 }
2024
P.V. Phani Kumar9cd95102016-03-09 12:35:23 +05302025 if (check_aboot_addr_range_overlap((uint32_t)fdt,
Mayank Grover2533aab2018-02-23 18:06:07 +05302026 (fdt_totalsize(fdt) + DTB_PAD_SIZE + cmdline_len))) {
P.V. Phani Kumar9cd95102016-03-09 12:35:23 +05302027 dprintf(CRITICAL, "Error: Fdt addresses overlap with aboot addresses.\n");
2028 return ret;
2029 }
2030
Deepa Dinamani1c970732013-04-19 14:23:01 -07002031 /* Add padding to make space for new nodes and properties. */
Mayank Grover2533aab2018-02-23 18:06:07 +05302032 ret = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + DTB_PAD_SIZE + cmdline_len);
Deepa Dinamani1c970732013-04-19 14:23:01 -07002033 if (ret!= 0)
2034 {
2035 dprintf(CRITICAL, "Failed to move/resize dtb buffer: %d\n", ret);
2036 return ret;
2037 }
2038
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002039 /* Get offset of the memory node */
2040 ret = fdt_path_offset(fdt, "/memory");
2041 if (ret < 0)
2042 {
2043 dprintf(CRITICAL, "Could not find memory node.\n");
2044 return ret;
2045 }
2046
2047 offset = ret;
2048
2049 ret = target_dev_tree_mem(fdt, offset);
2050 if(ret)
2051 {
2052 dprintf(CRITICAL, "ERROR: Cannot update memory node\n");
2053 return ret;
2054 }
2055
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002056 /* Get offset of the chosen node */
2057 ret = fdt_path_offset(fdt, "/chosen");
2058 if (ret < 0)
2059 {
2060 dprintf(CRITICAL, "Could not find chosen node.\n");
2061 return ret;
2062 }
2063
2064 offset = ret;
Maria Yuabde9542014-07-07 14:49:34 +08002065 if (cmdline)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002066 {
Maria Yuabde9542014-07-07 14:49:34 +08002067 /* Adding the cmdline to the chosen node */
2068 ret = fdt_appendprop_string(fdt, offset, (const char*)"bootargs", (const void*)cmdline);
2069 if (ret)
2070 {
2071 dprintf(CRITICAL, "ERROR: Cannot update chosen node [bootargs]\n");
2072 return ret;
2073 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002074 }
2075
lijuangc76a7632017-12-07 14:37:56 +08002076#if ENABLE_KASLRSEED_SUPPORT
lijuang0ac31232018-10-19 17:53:36 +08002077 if (!scm_random((uintptr_t *)&kaslrseed, sizeof(kaslrseed))) {
lijuangc76a7632017-12-07 14:37:56 +08002078 /* Adding Kaslr Seed to the chosen node */
2079 ret = fdt_appendprop_u64 (fdt, offset, (const char *)"kaslr-seed", (uint64_t)kaslrseed);
2080 if (ret)
2081 dprintf(CRITICAL, "ERROR: Cannot update chosen node [kaslr-seed] - 0x%x\n", ret);
2082 else
2083 dprintf(CRITICAL, "kaslr-Seed is added to chosen node\n");
2084 } else {
2085 dprintf(CRITICAL, "ERROR: Cannot generate Kaslr Seed\n");
2086 }
2087#endif
2088
Joonwoo Parka5b5f492014-02-13 18:24:48 -08002089 if (ramdisk_size) {
2090 /* Adding the initrd-start to the chosen node */
2091 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-start",
2092 (uint32_t)ramdisk);
2093 if (ret)
2094 {
2095 dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-start]\n");
2096 return ret;
2097 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002098
Joonwoo Parka5b5f492014-02-13 18:24:48 -08002099 /* Adding the initrd-end to the chosen node */
2100 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-end",
2101 ((uint32_t)ramdisk + ramdisk_size));
2102 if (ret)
2103 {
2104 dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-end]\n");
2105 return ret;
2106 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002107 }
2108
Mayank Grovera9ffe802019-06-03 14:08:40 +05302109#if ENABLE_BOOTDEVICE_MOUNT || DYNAMIC_PARTITION_SUPPORT
Kishor PK536904a2017-07-13 17:18:59 +05302110 /* Update fstab node */
2111 dprintf(SPEW, "Start of fstab node update:%zu ms\n", platform_get_sclk_count());
2112 if (update_fstab_node(fdt) != 0) {
2113 dprintf(CRITICAL, "ERROR: Cannot update fstab node\n");
2114 return ret;
2115 }
2116 dprintf(SPEW, "End of fstab node update:%zu ms\n", platform_get_sclk_count());
2117#endif
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002118 fdt_pack(fdt);
2119
Channagoud Kadabiffaea422014-12-05 15:45:41 -08002120#if ENABLE_PARTIAL_GOODS_SUPPORT
2121 update_partial_goods_dtb_nodes(fdt);
2122#endif
2123
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07002124 return ret;
2125}
Kishor PK536904a2017-07-13 17:18:59 +05302126
Mayank Grovera9ffe802019-06-03 14:08:40 +05302127#if ENABLE_BOOTDEVICE_MOUNT || DYNAMIC_PARTITION_SUPPORT
Kishor PK536904a2017-07-13 17:18:59 +05302128/*Update device tree for fstab node */
2129static int update_fstab_node(void *fdt)
2130{
2131 int ret = 0;
2132 int str_len = 0;
2133 int parent_offset = 0;
2134 int subnode_offset = 0;
2135 int prop_length = 0;
2136 int prefix_string_len = 0;
2137 char *node_name = NULL;
2138 char *boot_dev_buf = NULL;
2139 char *new_str = NULL;
2140 char *prefix_str = NULL;
2141 char *suffix_str = NULL;
2142 const struct fdt_property *prop = NULL;
Mayank Grovera9ffe802019-06-03 14:08:40 +05302143 struct fstab_node table = target_dynamic_partition_supported() ?
2144 dynamic_fstab_table :
2145 fstab_table;
Kishor PK536904a2017-07-13 17:18:59 +05302146
2147 /* Find the parent node */
Mayank Grovera9ffe802019-06-03 14:08:40 +05302148 parent_offset = fdt_path_offset(fdt, table.parent_node);
Kishor PK536904a2017-07-13 17:18:59 +05302149 if (parent_offset < 0) {
2150 dprintf(CRITICAL, "Failed to get parent node: fstab error: %d\n", parent_offset);
2151 return -1;
2152 }
2153 dprintf(SPEW, "Node: %s found.\n", fdt_get_name(fdt, parent_offset, NULL));
2154
Mayank Grovera9ffe802019-06-03 14:08:40 +05302155 if (!target_dynamic_partition_supported())
2156 {
2157 /* Get boot device type */
2158 boot_dev_buf = (char *) malloc(sizeof(char) * BOOT_DEV_MAX_LEN);
2159 if (!boot_dev_buf) {
2160 dprintf(CRITICAL, "Failed to allocate memory for boot device\n");
2161 return -1;
2162 }
2163
2164 new_str = (char *) malloc(sizeof(char) * NODE_PROPERTY_MAX_LEN);
2165 if (!new_str) {
2166 dprintf(CRITICAL, "Failed to allocate memory for node property string\n");
2167 return -1;
2168 }
2169
2170 platform_boot_dev_cmdline(boot_dev_buf);
Kishor PK536904a2017-07-13 17:18:59 +05302171 }
2172
Kishor PK536904a2017-07-13 17:18:59 +05302173 /* Get properties of all sub nodes */
Mayank Grovera9ffe802019-06-03 14:08:40 +05302174 for (subnode_offset = fdt_first_subnode(fdt, parent_offset);
2175 subnode_offset >= 0;
2176 subnode_offset = fdt_next_subnode(fdt, subnode_offset)) {
2177 prop = fdt_get_property(fdt, subnode_offset, table.node_prop, &prop_length);
Kishor PK536904a2017-07-13 17:18:59 +05302178 node_name = (char *)(uintptr_t)fdt_get_name(fdt, subnode_offset, NULL);
2179 if (!prop) {
Mayank Grovera9ffe802019-06-03 14:08:40 +05302180 dprintf(CRITICAL, "Property:%s is not found for sub node:%s\n", table.node_prop, node_name);
Kishor PK536904a2017-07-13 17:18:59 +05302181 } else {
Mayank Grovera9ffe802019-06-03 14:08:40 +05302182 dprintf(CRITICAL, "Property:%s found for sub node:%s\tproperty:%s\n", table.node_prop, node_name, prop->data);
2183
2184 /* For Dynamic partition support disable firmware fstab nodes. */
2185 if (target_dynamic_partition_supported())
2186 {
2187 dprintf (INFO, "Disabling node status :%s\n", node_name);
2188 ret = fdt_setprop (fdt, subnode_offset, table.node_prop, "disabled",
2189 (strlen("disabled") + 1));
2190 if (ret)
2191 {
2192 dprintf(CRITICAL, "ERROR: Failed to disable Node: %s\n", node_name);
2193 }
2194 continue;
2195 }
2196
Kishor PK536904a2017-07-13 17:18:59 +05302197 /* Pointer to fdt 'dev' property string that needs to update based on the 'androidboot.bootdevice' */
2198 memset(new_str, 0, NODE_PROPERTY_MAX_LEN);
2199 prefix_str = (char *)prop->data;
2200 if (strlen(prefix_str) > NODE_PROPERTY_MAX_LEN) {
2201 dprintf(CRITICAL, "Property string length is greater than node property max length\n");
2202 continue;
2203 }
Mayank Grovera9ffe802019-06-03 14:08:40 +05302204 suffix_str = strstr(prefix_str, table.device_path_id);
Kishor PK536904a2017-07-13 17:18:59 +05302205 if (!suffix_str) {
2206 dprintf(CRITICAL, "Property is not proper to update\n");
2207 continue;
2208 }
Mayank Grovera9ffe802019-06-03 14:08:40 +05302209 suffix_str += strlen(table.device_path_id);
Kishor PK536904a2017-07-13 17:18:59 +05302210 prefix_string_len = strlen(prefix_str) - (strlen(suffix_str) - 1);
2211 suffix_str = strstr((suffix_str + 1), "/");
2212 str_len = strlcpy(new_str, prefix_str, prefix_string_len);
2213 if (!str_len) {
2214 dprintf(CRITICAL, "Property length is not proper to update\n");
2215 continue;
2216 }
2217 str_len = strlcat(new_str, boot_dev_buf, strlen(prefix_str));
2218 if (!str_len) {
2219 dprintf(CRITICAL, "Property length is not proper to update\n");
2220 continue;
2221 }
2222 str_len = strlcat(new_str, suffix_str, strlen(prefix_str));
2223 if (!str_len) {
2224 dprintf(CRITICAL, "Property length is not proper to update\n");
2225 continue;
2226 }
2227 /* Update the new property in the memory */
2228 memscpy(prefix_str, strlen(prefix_str), new_str, strlen(new_str) + 1);
2229 /* Update the property with new value */
Mayank Grovera9ffe802019-06-03 14:08:40 +05302230 ret = fdt_setprop(fdt, subnode_offset, table.node_prop, (const void *)prefix_str, strlen(prefix_str) + 1);
Kishor PK536904a2017-07-13 17:18:59 +05302231 if(ret) {
2232 dprintf(CRITICAL, "Failed to update the node with new property\n");
2233 continue;
2234 }
2235 dprintf(CRITICAL, "Updated %s with new property %s\n", node_name, prop->data);
2236 }
2237 }
2238 if (boot_dev_buf)
2239 free(boot_dev_buf);
2240 if (new_str)
2241 free(new_str);
2242 return ret;
2243}
2244#endif