blob: ecff9266416183fbbda5860b3adae43d3c045d75 [file] [log] [blame]
Kishor PK536904a2017-07-13 17:18:59 +05301/* Copyright (c) 2012-2015,2017 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>
vijay kumar4f4405f2014-08-08 11:49:53 +053040#include <target.h>
Channagoud Kadabiffaea422014-12-05 15:45:41 -080041#include <partial_goods.h>
Kishor PK536904a2017-07-13 17:18:59 +053042#include <boot_device.h>
43#include <platform.h>
lijuangc76a7632017-12-07 14:37:56 +080044#include <scm.h>
Kishor PK536904a2017-07-13 17:18:59 +053045
46#define BOOT_DEV_MAX_LEN 64
47#define NODE_PROPERTY_MAX_LEN 64
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -070048
Joel Kingaa335dc2013-06-03 16:11:08 -070049struct dt_entry_v1
50{
51 uint32_t platform_id;
52 uint32_t variant_id;
53 uint32_t soc_rev;
54 uint32_t offset;
55 uint32_t size;
56};
57
Kishor PK536904a2017-07-13 17:18:59 +053058#if ENABLE_BOOTDEVICE_MOUNT
59/* Look up table for fstab node */
60struct fstab_node
61{
62 const char *parent_node;
63 const char *node_prop;
64 const char *device_path_id;
65};
66
67static struct fstab_node fstab_table =
68{
69 "/firmware/android/fstab", "dev", "/soc/"
70};
71#endif
72
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -070073static struct dt_mem_node_info mem_node;
Lijuan Gao9f152862014-08-18 13:45:24 +080074static int platform_dt_absolute_match(struct dt_entry *cur_dt_entry, struct dt_entry_node *dt_list);
75static struct dt_entry *platform_dt_match_best(struct dt_entry_node *dt_list);
76static int update_dtb_entry_node(struct dt_entry_node *dt_list, uint32_t dtb_info);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -070077extern int target_is_emmc_boot(void);
78extern uint32_t target_dev_tree_mem(void *fdt, uint32_t memory_node_offset);
Kishor PK536904a2017-07-13 17:18:59 +053079static int update_fstab_node(void *fdt);
80
Deepa Dinamanic55f01b2013-05-30 14:05:56 -070081/* TODO: This function needs to be moved to target layer to check violations
82 * against all the other regions as well.
83 */
Vijay Kumar Pendoti9c002ad2016-03-09 13:52:45 +053084extern int check_aboot_addr_range_overlap(uintptr_t start, uint32_t size);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -070085
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +053086int fdt_check_header_ext(const void *fdt)
87{
88 uintptr_t fdt_start, fdt_end;
89 fdt_start = (uintptr_t)fdt;
90 if(fdt_start + fdt_totalsize(fdt) < fdt_start)
91 {
92 dprintf(CRITICAL,"Integer over in fdt header %s\t%d",__func__,__LINE__);
93 return FDT_ERR_BADOFFSET;
94 }
95 fdt_end = fdt_start + fdt_totalsize(fdt);
96
97 if (((uint64_t)fdt_start + (uint64_t)fdt_off_dt_struct(fdt) + (uint64_t)fdt_size_dt_struct(fdt)) > UINT_MAX)
98 return FDT_ERR_BADOFFSET;
99
100 if ((fdt_start + fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt)) > fdt_end)
101 return FDT_ERR_BADOFFSET;
102
103 if (((uint64_t)fdt_start + (uint64_t)fdt_off_dt_strings(fdt) + (uint64_t)fdt_size_dt_strings(fdt)) > UINT_MAX)
104 return FDT_ERR_BADOFFSET;
105
106 if ((fdt_start + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)) > fdt_end)
107 return FDT_ERR_BADOFFSET;
108
109 return 0;
110}
111
Shashank Mittalc0f10282013-07-15 14:53:31 -0700112/* Returns soc version if platform id and hardware id matches
113 otherwise return 0xFFFFFFFF */
114#define INVALID_SOC_REV_ID 0XFFFFFFFF
Lijuan Gao9f152862014-08-18 13:45:24 +0800115
116/* Add function to allocate dt entry list, used for recording
117* the entry which conform to platform_dt_absolute_match()
118*/
119static struct dt_entry_node *dt_entry_list_init(void)
120{
121 struct dt_entry_node *dt_node_member = NULL;
122
123 dt_node_member = (struct dt_entry_node *)
124 malloc(sizeof(struct dt_entry_node));
125
126 ASSERT(dt_node_member);
127
128 list_clear_node(&dt_node_member->node);
129 dt_node_member->dt_entry_m = (struct dt_entry *)
130 malloc(sizeof(struct dt_entry));
131 ASSERT(dt_node_member->dt_entry_m);
132
133 memset(dt_node_member->dt_entry_m ,0 ,sizeof(struct dt_entry));
134 return dt_node_member;
135}
136
137static void insert_dt_entry_in_queue(struct dt_entry_node *dt_list, struct dt_entry_node *dt_node_member)
138{
139 list_add_tail(&dt_list->node, &dt_node_member->node);
140}
141
142static void dt_entry_list_delete(struct dt_entry_node *dt_node_member)
143{
144 if (list_in_list(&dt_node_member->node)) {
145 list_delete(&dt_node_member->node);
146 free(dt_node_member->dt_entry_m);
147 free(dt_node_member);
148 }
149}
150
151static int dev_tree_compatible(void *dtb, uint32_t dtb_size, struct dt_entry_node *dtb_list)
Dima Zavinc46f8382013-05-03 12:23:06 -0700152{
153 int root_offset;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700154 const void *prop = NULL;
155 const char *plat_prop = NULL;
156 const char *board_prop = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800157 const char *pmic_prop = NULL;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700158 char *model = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800159 struct dt_entry *cur_dt_entry;
160 struct dt_entry *dt_entry_array = NULL;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700161 struct board_id *board_data = NULL;
162 struct plat_id *platform_data = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800163 struct pmic_id *pmic_data = NULL;
Dima Zavinc46f8382013-05-03 12:23:06 -0700164 int len;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700165 int len_board_id;
166 int len_plat_id;
167 int min_plat_id_len = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800168 int len_pmic_id;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700169 uint32_t dtb_ver;
170 uint32_t num_entries = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800171 uint32_t i, j, k, n;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700172 uint32_t msm_data_count;
173 uint32_t board_data_count;
Lijuan Gao9f152862014-08-18 13:45:24 +0800174 uint32_t pmic_data_count;
Dima Zavinc46f8382013-05-03 12:23:06 -0700175
176 root_offset = fdt_path_offset(dtb, "/");
177 if (root_offset < 0)
178 return false;
179
180 prop = fdt_getprop(dtb, root_offset, "model", &len);
181 if (prop && len > 0) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700182 model = (char *) malloc(sizeof(char) * len);
183 ASSERT(model);
184 strlcpy(model, prop, len);
Dima Zavinc46f8382013-05-03 12:23:06 -0700185 } else {
vijay kumar89d36d82014-06-30 19:32:18 +0530186 dprintf(INFO, "model does not exist in device tree\n");
Dima Zavinc46f8382013-05-03 12:23:06 -0700187 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800188 /* Find the pmic-id prop from DTB , if pmic-id is present then
189 * the DTB is version 3, otherwise find the board-id prop from DTB ,
190 * if board-id is present then the DTB is version 2 */
191 pmic_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,pmic-id", &len_pmic_id);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700192 board_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,board-id", &len_board_id);
Lijuan Gao9f152862014-08-18 13:45:24 +0800193 if (pmic_prop && (len_pmic_id > 0) && board_prop && (len_board_id > 0)) {
194 if ((len_pmic_id % PMIC_ID_SIZE) || (len_board_id % BOARD_ID_SIZE))
195 {
196 dprintf(CRITICAL, "qcom,pmic-id(%d) or qcom,board-id(%d) in device tree is not a multiple of (%d %d)\n",
197 len_pmic_id, len_board_id, PMIC_ID_SIZE, BOARD_ID_SIZE);
198 return false;
199 }
200 dtb_ver = DEV_TREE_VERSION_V3;
201 min_plat_id_len = PLAT_ID_SIZE;
202 } else if (board_prop && len_board_id > 0) {
vijay kumar89d36d82014-06-30 19:32:18 +0530203 if (len_board_id % BOARD_ID_SIZE)
204 {
205 dprintf(CRITICAL, "qcom,board-id in device tree is (%d) not a multiple of (%d)\n",
206 len_board_id, BOARD_ID_SIZE);
207 return false;
208 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700209 dtb_ver = DEV_TREE_VERSION_V2;
210 min_plat_id_len = PLAT_ID_SIZE;
Lijuan Gao9f152862014-08-18 13:45:24 +0800211 } else {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700212 dtb_ver = DEV_TREE_VERSION_V1;
213 min_plat_id_len = DT_ENTRY_V1_SIZE;
214 }
215
216 /* Get the msm-id prop from DTB */
217 plat_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,msm-id", &len_plat_id);
218 if (!plat_prop || len_plat_id <= 0) {
Dima Zavinc46f8382013-05-03 12:23:06 -0700219 dprintf(INFO, "qcom,msm-id entry not found\n");
220 return false;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700221 } else if (len_plat_id % min_plat_id_len) {
222 dprintf(INFO, "qcom,msm-id in device tree is (%d) not a multiple of (%d)\n",
223 len_plat_id, min_plat_id_len);
Dima Zavinc46f8382013-05-03 12:23:06 -0700224 return false;
225 }
Dima Zavinc46f8382013-05-03 12:23:06 -0700226
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700227 /*
228 * If DTB version is '1' look for <x y z> pair in the DTB
229 * x: platform_id
230 * y: variant_id
231 * z: SOC rev
232 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800233 if (dtb_ver == DEV_TREE_VERSION_V1) {
234 cur_dt_entry = (struct dt_entry *)
235 malloc(sizeof(struct dt_entry));
Dima Zavinc46f8382013-05-03 12:23:06 -0700236
Lijuan Gao9f152862014-08-18 13:45:24 +0800237 if (!cur_dt_entry) {
238 dprintf(CRITICAL, "Out of memory\n");
239 return false;
240 }
241 memset(cur_dt_entry, 0, sizeof(struct dt_entry));
242
243 while (len_plat_id) {
244 cur_dt_entry->platform_id = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->platform_id);
245 cur_dt_entry->variant_id = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->variant_id);
246 cur_dt_entry->soc_rev = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->soc_rev);
247 cur_dt_entry->board_hw_subtype =
248 fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->variant_id) >> 0x18;
249 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
250 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
251 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
252 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
253 cur_dt_entry->offset = (uint32_t)dtb;
254 cur_dt_entry->size = dtb_size;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700255
256 dprintf(SPEW, "Found an appended flattened device tree (%s - %u %u 0x%x)\n",
Lijuan Gao9f152862014-08-18 13:45:24 +0800257 *model ? model : "unknown",
258 cur_dt_entry->platform_id, cur_dt_entry->variant_id, cur_dt_entry->soc_rev);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700259
Lijuan Gao9f152862014-08-18 13:45:24 +0800260 if (platform_dt_absolute_match(cur_dt_entry, dtb_list)) {
261 dprintf(SPEW, "Device tree exact match the board: <%u %u 0x%x> != <%u %u 0x%x>\n",
262 cur_dt_entry->platform_id,
263 cur_dt_entry->variant_id,
264 cur_dt_entry->soc_rev,
265 board_platform_id(),
266 board_hardware_id(),
267 board_soc_version());
268
269 } else {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700270 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 +0800271 cur_dt_entry->platform_id,
272 cur_dt_entry->variant_id,
273 cur_dt_entry->soc_rev,
274 board_platform_id(),
275 board_hardware_id(),
276 board_soc_version());
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700277 plat_prop += DT_ENTRY_V1_SIZE;
278 len_plat_id -= DT_ENTRY_V1_SIZE;
279 continue;
280 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700281 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800282 free(cur_dt_entry);
283
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700284 }
285 /*
Lijuan Gao9f152862014-08-18 13:45:24 +0800286 * If DTB Version is '3' then we have split DTB with board & msm data & pmic
287 * populated saperately in board-id & msm-id & pmic-id prop respectively.
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700288 * Extract the data & prepare a look up table
289 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800290 else if (dtb_ver == DEV_TREE_VERSION_V2 || dtb_ver == DEV_TREE_VERSION_V3) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700291 board_data_count = (len_board_id / BOARD_ID_SIZE);
292 msm_data_count = (len_plat_id / PLAT_ID_SIZE);
Lijuan Gao9f152862014-08-18 13:45:24 +0800293 /* If dtb version is v2.0, the pmic_data_count will be <= 0 */
294 pmic_data_count = (len_pmic_id / PMIC_ID_SIZE);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700295
Lijuan Gao9f152862014-08-18 13:45:24 +0800296 /* If we are using dtb v3.0, then we have split board, msm & pmic data in the DTB
297 * If we are using dtb v2.0, then we have split board & msmdata in the DTB
298 */
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700299 board_data = (struct board_id *) malloc(sizeof(struct board_id) * (len_board_id / BOARD_ID_SIZE));
300 ASSERT(board_data);
301 platform_data = (struct plat_id *) malloc(sizeof(struct plat_id) * (len_plat_id / PLAT_ID_SIZE));
302 ASSERT(platform_data);
Lijuan Gao9f152862014-08-18 13:45:24 +0800303 if (dtb_ver == DEV_TREE_VERSION_V3) {
304 pmic_data = (struct pmic_id *) malloc(sizeof(struct pmic_id) * (len_pmic_id / PMIC_ID_SIZE));
305 ASSERT(pmic_data);
306 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700307 i = 0;
308
309 /* Extract board data from DTB */
Lijuan Gao9f152862014-08-18 13:45:24 +0800310 for(i = 0 ; i < board_data_count; i++) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700311 board_data[i].variant_id = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id);
312 board_data[i].platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->platform_subtype);
Lijuan Gao9f152862014-08-18 13:45:24 +0800313 /* For V2/V3 version of DTBs we have platform version field as part
314 * of variant ID, in such case the subtype will be mentioned as 0x0
315 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
316 * SS -- Subtype
317 * PM -- Platform major version
318 * Pm -- Platform minor version
319 * PH -- Platform hardware CDP/MTP
320 * In such case to make it compatible with LK algorithm move the subtype
321 * from variant_id to subtype field
322 */
323 if (board_data[i].platform_subtype == 0)
324 board_data[i].platform_subtype =
325 fdt32_to_cpu(((struct board_id *)board_prop)->variant_id) >> 0x18;
326
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700327 len_board_id -= sizeof(struct board_id);
328 board_prop += sizeof(struct board_id);
329 }
330
331 /* Extract platform data from DTB */
Lijuan Gao9f152862014-08-18 13:45:24 +0800332 for(i = 0 ; i < msm_data_count; i++) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700333 platform_data[i].platform_id = fdt32_to_cpu(((struct plat_id *)plat_prop)->platform_id);
334 platform_data[i].soc_rev = fdt32_to_cpu(((struct plat_id *)plat_prop)->soc_rev);
335 len_plat_id -= sizeof(struct plat_id);
336 plat_prop += sizeof(struct plat_id);
337 }
338
Lijuan Gao9f152862014-08-18 13:45:24 +0800339 if (dtb_ver == DEV_TREE_VERSION_V3 && pmic_prop) {
340 /* Extract pmic data from DTB */
341 for(i = 0 ; i < pmic_data_count; i++) {
342 pmic_data[i].pmic_version[0]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[0]);
343 pmic_data[i].pmic_version[1]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[1]);
344 pmic_data[i].pmic_version[2]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[2]);
345 pmic_data[i].pmic_version[3]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[3]);
346 len_pmic_id -= sizeof(struct pmic_id);
347 pmic_prop += sizeof(struct pmic_id);
348 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700349
Lijuan Gao9f152862014-08-18 13:45:24 +0800350 /* We need to merge board & platform data into dt entry structure */
351 num_entries = msm_data_count * board_data_count * pmic_data_count;
352 } else {
353 /* We need to merge board & platform data into dt entry structure */
354 num_entries = msm_data_count * board_data_count;
355 }
vijay kumar89d36d82014-06-30 19:32:18 +0530356
Lijuan Gao9f152862014-08-18 13:45:24 +0800357 if ((((uint64_t)msm_data_count * (uint64_t)board_data_count * (uint64_t)pmic_data_count) !=
358 msm_data_count * board_data_count * pmic_data_count) ||
359 (((uint64_t)msm_data_count * (uint64_t)board_data_count) != msm_data_count * board_data_count)) {
360
361 free(board_data);
362 free(platform_data);
363 if (pmic_data)
364 free(pmic_data);
365 if (model)
366 free(model);
367 return false;
368 }
369
370 dt_entry_array = (struct dt_entry*) malloc(sizeof(struct dt_entry) * num_entries);
371 ASSERT(dt_entry_array);
372
373 /* If we have '<X>; <Y>; <Z>' as platform data & '<A>; <B>; <C>' as board data.
374 * Then dt entry should look like
375 * <X ,A >;<X, B>;<X, C>;
376 * <Y ,A >;<Y, B>;<Y, C>;
377 * <Z ,A >;<Z, B>;<Z, C>;
378 */
379 i = 0;
380 k = 0;
381 n = 0;
382 for (i = 0; i < msm_data_count; i++) {
383 for (j = 0; j < board_data_count; j++) {
384 if (dtb_ver == DEV_TREE_VERSION_V3 && pmic_prop) {
385 for (n = 0; n < pmic_data_count; n++) {
386 dt_entry_array[k].platform_id = platform_data[i].platform_id;
387 dt_entry_array[k].soc_rev = platform_data[i].soc_rev;
388 dt_entry_array[k].variant_id = board_data[j].variant_id;
389 dt_entry_array[k].board_hw_subtype = board_data[j].platform_subtype;
390 dt_entry_array[k].pmic_rev[0]= pmic_data[n].pmic_version[0];
391 dt_entry_array[k].pmic_rev[1]= pmic_data[n].pmic_version[1];
392 dt_entry_array[k].pmic_rev[2]= pmic_data[n].pmic_version[2];
393 dt_entry_array[k].pmic_rev[3]= pmic_data[n].pmic_version[3];
394 dt_entry_array[k].offset = (uint32_t)dtb;
395 dt_entry_array[k].size = dtb_size;
396 k++;
397 }
398
399 } else {
400 dt_entry_array[k].platform_id = platform_data[i].platform_id;
401 dt_entry_array[k].soc_rev = platform_data[i].soc_rev;
402 dt_entry_array[k].variant_id = board_data[j].variant_id;
403 dt_entry_array[k].board_hw_subtype = board_data[j].platform_subtype;
404 dt_entry_array[k].pmic_rev[0]= board_pmic_target(0);
405 dt_entry_array[k].pmic_rev[1]= board_pmic_target(1);
406 dt_entry_array[k].pmic_rev[2]= board_pmic_target(2);
407 dt_entry_array[k].pmic_rev[3]= board_pmic_target(3);
408 dt_entry_array[k].offset = (uint32_t)dtb;
409 dt_entry_array[k].size = dtb_size;
vijay kumar89d36d82014-06-30 19:32:18 +0530410 k++;
411 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700412 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800413 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700414
Lijuan Gao9f152862014-08-18 13:45:24 +0800415 for (i=0 ;i < num_entries; i++) {
416 dprintf(SPEW, "Found an appended flattened device tree (%s - %u %u %u 0x%x)\n",
417 *model ? model : "unknown",
418 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 +0530419
Lijuan Gao9f152862014-08-18 13:45:24 +0800420 if (platform_dt_absolute_match(&(dt_entry_array[i]), dtb_list)) {
421 dprintf(SPEW, "Device tree exact match the board: <%u %u %u 0x%x> == <%u %u %u 0x%x>\n",
422 dt_entry_array[i].platform_id,
423 dt_entry_array[i].variant_id,
424 dt_entry_array[i].soc_rev,
425 dt_entry_array[i].board_hw_subtype,
426 board_platform_id(),
427 board_hardware_id(),
428 board_hardware_subtype(),
429 board_soc_version());
vijay kumar89d36d82014-06-30 19:32:18 +0530430
Lijuan Gao9f152862014-08-18 13:45:24 +0800431 } else {
432 dprintf(SPEW, "Device tree's msm_id doesn't match the board: <%u %u %u 0x%x> != <%u %u %u 0x%x>\n",
433 dt_entry_array[i].platform_id,
434 dt_entry_array[i].variant_id,
435 dt_entry_array[i].soc_rev,
436 dt_entry_array[i].board_hw_subtype,
437 board_platform_id(),
438 board_hardware_id(),
439 board_hardware_subtype(),
440 board_soc_version());
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700441 }
442 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800443
444 free(board_data);
445 free(platform_data);
446 if (pmic_data)
447 free(pmic_data);
448 free(dt_entry_array);
Dima Zavinc46f8382013-05-03 12:23:06 -0700449 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800450 if (model)
vijay kumar89d36d82014-06-30 19:32:18 +0530451 free(model);
Lijuan Gao9f152862014-08-18 13:45:24 +0800452 return true;
Dima Zavinc46f8382013-05-03 12:23:06 -0700453}
454
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800455/*
Dima Zavin77e41f32013-03-06 16:10:43 -0800456 * Will relocate the DTB to the tags addr if the device tree is found and return
457 * its address
458 *
459 * Arguments: kernel - Start address of the kernel loaded in RAM
460 * tags - Start address of the tags loaded in RAM
Channagoud Kadabi704cd562013-04-25 15:19:59 -0700461 * kernel_size - Size of the kernel in bytes
462 *
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800463 * Return Value: DTB address : If appended device tree is found
Dima Zavin77e41f32013-03-06 16:10:43 -0800464 * 'NULL' : Otherwise
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800465 */
Matthew Qinbb7923d2015-02-09 10:56:09 +0800466void *dev_tree_appended(void *kernel, uint32_t kernel_size, uint32_t dtb_offset, void *tags)
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800467{
Parth Dixit97e47bb2016-03-07 17:20:44 +0530468 uintptr_t kernel_end = (uintptr_t)kernel + kernel_size;
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800469 uint32_t app_dtb_offset = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800470 void *dtb = NULL;
Shashank Mittalc0f10282013-07-15 14:53:31 -0700471 void *bestmatch_tag = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800472 struct dt_entry *best_match_dt_entry = NULL;
Shashank Mittalc0f10282013-07-15 14:53:31 -0700473 uint32_t bestmatch_tag_size;
Lijuan Gao9f152862014-08-18 13:45:24 +0800474 struct dt_entry_node *dt_entry_queue = NULL;
475 struct dt_entry_node *dt_node_tmp1 = NULL;
476 struct dt_entry_node *dt_node_tmp2 = NULL;
477
Lijuan Gao9f152862014-08-18 13:45:24 +0800478 /* Initialize the dtb entry node*/
479 dt_entry_queue = (struct dt_entry_node *)
480 malloc(sizeof(struct dt_entry_node));
481
482 if (!dt_entry_queue) {
483 dprintf(CRITICAL, "Out of memory\n");
484 return NULL;
485 }
486 list_initialize(&dt_entry_queue->node);
487
Matthew Qinbb7923d2015-02-09 10:56:09 +0800488 if (dtb_offset)
489 app_dtb_offset = dtb_offset;
490 else
491 memcpy((void*) &app_dtb_offset, (void*) (kernel + DTB_OFFSET), sizeof(uint32_t));
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800492
vijay kumare2a5ea82014-06-25 12:24:14 +0530493 if (((uintptr_t)kernel + (uintptr_t)app_dtb_offset) < (uintptr_t)kernel) {
494 return NULL;
495 }
Parth Dixit97e47bb2016-03-07 17:20:44 +0530496 dtb = (void *)((uintptr_t)kernel + app_dtb_offset);
497
vijay kumare2a5ea82014-06-25 12:24:14 +0530498 while (((uintptr_t)dtb + sizeof(struct fdt_header)) < (uintptr_t)kernel_end) {
Dima Zavinc46f8382013-05-03 12:23:06 -0700499 struct fdt_header dtb_hdr;
500 uint32_t dtb_size;
Dima Zavin77e41f32013-03-06 16:10:43 -0800501
Dima Zavinc46f8382013-05-03 12:23:06 -0700502 /* the DTB could be unaligned, so extract the header,
503 * and operate on it separately */
504 memcpy(&dtb_hdr, dtb, sizeof(struct fdt_header));
505 if (fdt_check_header((const void *)&dtb_hdr) != 0 ||
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +0530506 fdt_check_header_ext((const void *)&dtb_hdr) != 0 ||
vijay kumare2a5ea82014-06-25 12:24:14 +0530507 ((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) < (uintptr_t)dtb) ||
508 ((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) > (uintptr_t)kernel_end))
Dima Zavinc46f8382013-05-03 12:23:06 -0700509 break;
510 dtb_size = fdt_totalsize(&dtb_hdr);
511
Lijuan Gao9f152862014-08-18 13:45:24 +0800512 dev_tree_compatible(dtb, dtb_size, dt_entry_queue);
Dima Zavinc46f8382013-05-03 12:23:06 -0700513
514 /* goto the next device tree if any */
515 dtb += dtb_size;
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800516 }
Dima Zavinc46f8382013-05-03 12:23:06 -0700517
Lijuan Gao9f152862014-08-18 13:45:24 +0800518 best_match_dt_entry = platform_dt_match_best(dt_entry_queue);
519 if (best_match_dt_entry){
520 bestmatch_tag = (void *)best_match_dt_entry->offset;
521 bestmatch_tag_size = best_match_dt_entry->size;
522 dprintf(INFO, "Best match DTB tags %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
523 best_match_dt_entry->platform_id, best_match_dt_entry->variant_id,
524 best_match_dt_entry->board_hw_subtype, best_match_dt_entry->soc_rev,
525 best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],
526 best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],
527 best_match_dt_entry->offset, best_match_dt_entry->size);
528 dprintf(INFO, "Using pmic info 0x%0x/0x%x/0x%x/0x%0x for device 0x%0x/0x%x/0x%x/0x%0x\n",
529 best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],
530 best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],
531 board_pmic_target(0), board_pmic_target(1),
532 board_pmic_target(2), board_pmic_target(3));
533 }
534 /* free queue's memory */
535 list_for_every_entry(&dt_entry_queue->node, dt_node_tmp1, dt_node, node) {
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -0800536 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +0800537 dt_entry_list_delete(dt_node_tmp1);
538 dt_node_tmp1 = dt_node_tmp2;
539 }
540
Shashank Mittalc0f10282013-07-15 14:53:31 -0700541 if(bestmatch_tag) {
Parth Dixitc2f0cb92016-03-10 10:40:14 +0530542 if (check_aboot_addr_range_overlap((uintptr_t)tags, bestmatch_tag_size)) {
543 dprintf(CRITICAL, "Tags addresses overlap with aboot addresses.\n");
544 return NULL;
545 }
Shashank Mittalc0f10282013-07-15 14:53:31 -0700546 memcpy(tags, bestmatch_tag, bestmatch_tag_size);
547 /* clear out the old DTB magic so kernel doesn't find it */
548 *((uint32_t *)(kernel + app_dtb_offset)) = 0;
549 return tags;
550 }
551
Dima Zavinc46f8382013-05-03 12:23:06 -0700552 dprintf(CRITICAL, "DTB offset is incorrect, kernel image does not have appended DTB\n");
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800553
David Ng59c4a782015-05-14 15:51:44 -0700554 dprintf(INFO, "Device info 0x%08x/%08x/0x%08x/%u, pmic 0x%0x/0x%x/0x%x/0x%0x\n",
555 board_platform_id(), board_soc_version(),
556 board_target_id(), board_hardware_subtype(),
557 board_pmic_target(0), board_pmic_target(1),
558 board_pmic_target(2), board_pmic_target(3));
Dima Zavin77e41f32013-03-06 16:10:43 -0800559 return NULL;
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800560}
561
Joel Kingaa335dc2013-06-03 16:11:08 -0700562/* Returns 0 if the device tree is valid. */
Deepa Dinamani87252952013-09-09 13:58:27 -0700563int dev_tree_validate(struct dt_table *table, unsigned int page_size, uint32_t *dt_hdr_size)
Joel Kingaa335dc2013-06-03 16:11:08 -0700564{
565 int dt_entry_size;
Channagoud Kadabid87c2772014-06-20 15:41:55 -0700566 uint64_t hdr_size;
Joel Kingaa335dc2013-06-03 16:11:08 -0700567
568 /* Validate the device tree table header */
569 if(table->magic != DEV_TREE_MAGIC) {
570 dprintf(CRITICAL, "ERROR: Bad magic in device tree table \n");
571 return -1;
572 }
573
574 if (table->version == DEV_TREE_VERSION_V1) {
575 dt_entry_size = sizeof(struct dt_entry_v1);
576 } else if (table->version == DEV_TREE_VERSION_V2) {
Lijuan Gao9f152862014-08-18 13:45:24 +0800577 dt_entry_size = sizeof(struct dt_entry_v2);
578 } else if (table->version == DEV_TREE_VERSION_V3) {
Joel Kingaa335dc2013-06-03 16:11:08 -0700579 dt_entry_size = sizeof(struct dt_entry);
580 } else {
581 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
582 table->version);
583 return -1;
584 }
585
Channagoud Kadabid87c2772014-06-20 15:41:55 -0700586 hdr_size = (uint64_t)table->num_entries * dt_entry_size + DEV_TREE_HEADER_SIZE;
587
Deepa Dinamani87252952013-09-09 13:58:27 -0700588 /* Roundup to page_size. */
589 hdr_size = ROUNDUP(hdr_size, page_size);
590
Channagoud Kadabid87c2772014-06-20 15:41:55 -0700591 if (hdr_size > UINT_MAX)
592 return -1;
593 else
594 *dt_hdr_size = hdr_size & UINT_MAX;
Joel Kingaa335dc2013-06-03 16:11:08 -0700595
596 return 0;
597}
598
Lijuan Gao9f152862014-08-18 13:45:24 +0800599static int platform_dt_absolute_match(struct dt_entry *cur_dt_entry, struct dt_entry_node *dt_list)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700600{
Lijuan Gaof8e95722014-12-23 03:03:12 -0500601 uint32_t cur_dt_hlos_ddr;
Lijuan Gao9f152862014-08-18 13:45:24 +0800602 uint32_t cur_dt_hw_platform;
603 uint32_t cur_dt_hw_subtype;
604 uint32_t cur_dt_msm_id;
605 dt_node *dt_node_tmp = NULL;
Channagoud Kadabi571193a2014-02-05 13:58:49 -0800606
Lijuan Gao9f152862014-08-18 13:45:24 +0800607 /* Platform-id
608 * bit no |31 24|23 16|15 0|
609 * |reserved|foundry-id|msm-id|
610 */
611 cur_dt_msm_id = (cur_dt_entry->platform_id & 0x0000ffff);
612 cur_dt_hw_platform = (cur_dt_entry->variant_id & 0x000000ff);
Lijuan Gao0621b862014-09-02 10:02:52 +0800613 cur_dt_hw_subtype = (cur_dt_entry->board_hw_subtype & 0xff);
Lijuan Gao9f152862014-08-18 13:45:24 +0800614
Lijuan Gaof8e95722014-12-23 03:03:12 -0500615 /* Determine the bits 10:8 to check the DT with the DDR Size */
616 cur_dt_hlos_ddr = (cur_dt_entry->board_hw_subtype & 0x700);
Channagoud Kadabi571193a2014-02-05 13:58:49 -0800617
Lijuan Gao9f152862014-08-18 13:45:24 +0800618 /* 1. must match the msm_id, platform_hw_id, platform_subtype and DDR size
619 * soc, board major/minor, pmic major/minor must less than board info
620 * 2. find the matched DTB then return 1
621 * 3. otherwise return 0
Maria Yu2e2d2c22013-07-03 19:20:33 +0800622 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800623 if((cur_dt_msm_id == (board_platform_id() & 0x0000ffff)) &&
624 (cur_dt_hw_platform == board_hardware_id()) &&
625 (cur_dt_hw_subtype == board_hardware_subtype()) &&
Lijuan Gaof8e95722014-12-23 03:03:12 -0500626 (cur_dt_hlos_ddr == (target_get_hlos_subtype() & 0x700)) &&
Lijuan Gao9f152862014-08-18 13:45:24 +0800627 (cur_dt_entry->soc_rev <= board_soc_version()) &&
628 ((cur_dt_entry->variant_id & 0x00ffff00) <= (board_target_id() & 0x00ffff00)) &&
629 ((cur_dt_entry->pmic_rev[0] & 0x00ffff00) <= (board_pmic_target(0) & 0x00ffff00)) &&
630 ((cur_dt_entry->pmic_rev[1] & 0x00ffff00) <= (board_pmic_target(1) & 0x00ffff00)) &&
631 ((cur_dt_entry->pmic_rev[2] & 0x00ffff00) <= (board_pmic_target(2) & 0x00ffff00)) &&
632 ((cur_dt_entry->pmic_rev[3] & 0x00ffff00) <= (board_pmic_target(3) & 0x00ffff00))) {
Maria Yu2e2d2c22013-07-03 19:20:33 +0800633
Lijuan Gao9f152862014-08-18 13:45:24 +0800634 dt_node_tmp = dt_entry_list_init();
635 memcpy((char*)dt_node_tmp->dt_entry_m,(char*)cur_dt_entry, sizeof(struct dt_entry));
636
637 dprintf(SPEW, "Add DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
638 dt_node_tmp->dt_entry_m->platform_id, dt_node_tmp->dt_entry_m->variant_id,
639 dt_node_tmp->dt_entry_m->board_hw_subtype, dt_node_tmp->dt_entry_m->soc_rev,
640 dt_node_tmp->dt_entry_m->pmic_rev[0], dt_node_tmp->dt_entry_m->pmic_rev[1],
641 dt_node_tmp->dt_entry_m->pmic_rev[2], dt_node_tmp->dt_entry_m->pmic_rev[3],
642 dt_node_tmp->dt_entry_m->offset, dt_node_tmp->dt_entry_m->size);
643
644 insert_dt_entry_in_queue(dt_list, dt_node_tmp);
645 return 1;
646 }
647 return 0;
648}
649
650static int platform_dt_absolute_compat_match(struct dt_entry_node *dt_list, uint32_t dtb_info) {
651 struct dt_entry_node *dt_node_tmp1 = NULL;
652 struct dt_entry_node *dt_node_tmp2 = NULL;
653 uint32_t current_info = 0;
654 uint32_t board_info = 0;
655 uint32_t best_info = 0;
656 uint32_t current_pmic_model[4] = {0, 0, 0, 0};
657 uint32_t board_pmic_model[4] = {0, 0, 0, 0};
658 uint32_t best_pmic_model[4] = {0, 0, 0, 0};
659 uint32_t delete_current_dt = 0;
660 uint32_t i;
661
662 /* start to select the exact entry
663 * default to exact match 0, if find current DTB entry info is the same as board info,
664 * then exact match board info.
665 */
666 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
667 if (!dt_node_tmp1){
668 dprintf(SPEW, "Current node is the end\n");
669 break;
670 }
671 switch(dtb_info) {
672 case DTB_FOUNDRY:
673 current_info = ((dt_node_tmp1->dt_entry_m->platform_id) & 0x00ff0000);
Channagoud Kadabi4cffc272014-10-29 11:23:26 -0700674 board_info = board_foundry_id() << 16;
Lijuan Gao9f152862014-08-18 13:45:24 +0800675 break;
676 case DTB_PMIC_MODEL:
677 for (i = 0; i < 4; i++) {
678 current_pmic_model[i] = (dt_node_tmp1->dt_entry_m->pmic_rev[i] & 0xff);
679 board_pmic_model[i] = (board_pmic_target(i) & 0xff);
680 }
681 break;
Lijuan Gaof8e95722014-12-23 03:03:12 -0500682 case DTB_PANEL_TYPE:
683 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0x1800);
684 board_info = (target_get_hlos_subtype() & 0x1800);
685 break;
686 case DTB_BOOT_DEVICE:
687 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0xf0000);
688 board_info = (target_get_hlos_subtype() & 0xf0000);
689 break;
Lijuan Gao9f152862014-08-18 13:45:24 +0800690 default:
691 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
692 dtb_info);
Maria Yuca51ee22013-06-27 21:45:24 +0800693 return 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800694 }
695
696 if (dtb_info == DTB_PMIC_MODEL) {
697 if ((current_pmic_model[0] == board_pmic_model[0]) &&
698 (current_pmic_model[1] == board_pmic_model[1]) &&
699 (current_pmic_model[2] == board_pmic_model[2]) &&
700 (current_pmic_model[3] == board_pmic_model[3])) {
701
702 for (i = 0; i < 4; i++) {
703 best_pmic_model[i] = current_pmic_model[i];
704 }
705 break;
706 }
707 } else {
708 if (current_info == board_info) {
709 best_info = current_info;
710 break;
711 }
712 }
713 }
714
715 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
716 if (!dt_node_tmp1){
717 dprintf(SPEW, "Current node is the end\n");
718 break;
719 }
720 switch(dtb_info) {
721 case DTB_FOUNDRY:
722 current_info = ((dt_node_tmp1->dt_entry_m->platform_id) & 0x00ff0000);
723 break;
724 case DTB_PMIC_MODEL:
725 for (i = 0; i < 4; i++) {
726 current_pmic_model[i] = (dt_node_tmp1->dt_entry_m->pmic_rev[i] & 0xff);
727 }
728 break;
Lijuan Gaof8e95722014-12-23 03:03:12 -0500729 case DTB_PANEL_TYPE:
730 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0x1800);
731 break;
732 case DTB_BOOT_DEVICE:
733 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0xf0000);
734 break;
Lijuan Gao9f152862014-08-18 13:45:24 +0800735 default:
736 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
737 dtb_info);
738 return 0;
739 }
740
741 if (dtb_info == DTB_PMIC_MODEL) {
742 if ((current_pmic_model[0] != best_pmic_model[0]) ||
743 (current_pmic_model[1] != best_pmic_model[1]) ||
744 (current_pmic_model[2] != best_pmic_model[2]) ||
745 (current_pmic_model[3] != best_pmic_model[3])) {
746
747 delete_current_dt = 1;
748 }
749 } else {
750 if (current_info != best_info) {
751 delete_current_dt = 1;
752 }
753 }
754
755 if (delete_current_dt) {
756 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
757 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
758 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
759 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
760 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
761 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
762
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -0800763 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +0800764 dt_entry_list_delete(dt_node_tmp1);
765 dt_node_tmp1 = dt_node_tmp2;
766 delete_current_dt = 0;
Maria Yuca51ee22013-06-27 21:45:24 +0800767 }
768 }
Maria Yuca51ee22013-06-27 21:45:24 +0800769
Maria Yu2e2d2c22013-07-03 19:20:33 +0800770 return 1;
Maria Yuca51ee22013-06-27 21:45:24 +0800771}
772
Lijuan Gao9f152862014-08-18 13:45:24 +0800773static int update_dtb_entry_node(struct dt_entry_node *dt_list, uint32_t dtb_info) {
774 struct dt_entry_node *dt_node_tmp1 = NULL;
775 struct dt_entry_node *dt_node_tmp2 = NULL;
776 uint32_t current_info = 0;
777 uint32_t board_info = 0;
778 uint32_t best_info = 0;
779
780 /* start to select the best entry*/
781 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
782 if (!dt_node_tmp1){
783 dprintf(SPEW, "Current node is the end\n");
784 break;
785 }
786 switch(dtb_info) {
787 case DTB_SOC:
788 current_info = dt_node_tmp1->dt_entry_m->soc_rev;
789 board_info = board_soc_version();
790 break;
791 case DTB_MAJOR_MINOR:
792 current_info = ((dt_node_tmp1->dt_entry_m->variant_id) & 0x00ffff00);
793 board_info = (board_target_id() & 0x00ffff00);
794 break;
795 case DTB_PMIC0:
796 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[0]) & 0x00ffff00);
797 board_info = (board_pmic_target(0) & 0x00ffff00);
798 break;
799 case DTB_PMIC1:
800 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[1]) & 0x00ffff00);
801 board_info = (board_pmic_target(1) & 0x00ffff00);
802 break;
803 case DTB_PMIC2:
804 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[2]) & 0x00ffff00);
805 board_info = (board_pmic_target(2) & 0x00ffff00);
806 break;
807 case DTB_PMIC3:
808 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[3]) & 0x00ffff00);
809 board_info = (board_pmic_target(3) & 0x00ffff00);
810 break;
811 default:
812 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
813 dtb_info);
814 return 0;
815 }
816
817 if (current_info == board_info) {
818 best_info = current_info;
819 break;
820 }
821 if ((current_info < board_info) && (current_info > best_info)) {
822 best_info = current_info;
823 }
824 if (current_info < best_info) {
825 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
826 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
827 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
828 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
829 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
830 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
831
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -0800832 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +0800833 dt_entry_list_delete(dt_node_tmp1);
834 dt_node_tmp1 = dt_node_tmp2;
835 }
836 }
837
838 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
839 if (!dt_node_tmp1){
840 dprintf(SPEW, "Current node is the end\n");
841 break;
842 }
843 switch(dtb_info) {
844 case DTB_SOC:
845 current_info = dt_node_tmp1->dt_entry_m->soc_rev;
846 break;
847 case DTB_MAJOR_MINOR:
848 current_info = ((dt_node_tmp1->dt_entry_m->variant_id) & 0x00ffff00);
849 break;
850 case DTB_PMIC0:
851 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[0]) & 0x00ffff00);
852 break;
853 case DTB_PMIC1:
854 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[1]) & 0x00ffff00);
855 break;
856 case DTB_PMIC2:
857 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[2]) & 0x00ffff00);
858 break;
859 case DTB_PMIC3:
860 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[3]) & 0x00ffff00);
861 break;
862 default:
863 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
864 dtb_info);
865 return 0;
866 }
867
868 if (current_info != best_info) {
869 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
870 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
871 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
872 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
873 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
874 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
875
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -0800876 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +0800877 dt_entry_list_delete(dt_node_tmp1);
878 dt_node_tmp1 = dt_node_tmp2;
879 }
880 }
881 return 1;
882}
883
884static struct dt_entry *platform_dt_match_best(struct dt_entry_node *dt_list)
885{
886 struct dt_entry_node *dt_node_tmp1 = NULL;
887
888 /* check Foundry id
889 * the foundry id must exact match board founddry id, this is compatibility check,
890 * if couldn't find the exact match from DTB, will exact match 0x0.
891 */
892 if (!platform_dt_absolute_compat_match(dt_list, DTB_FOUNDRY))
893 return NULL;
894
895 /* check PMIC model
896 * the PMIC model must exact match board PMIC model, this is compatibility check,
897 * if couldn't find the exact match from DTB, will exact match 0x0.
898 */
899 if (!platform_dt_absolute_compat_match(dt_list, DTB_PMIC_MODEL))
900 return NULL;
901
Lijuan Gaof8e95722014-12-23 03:03:12 -0500902 /* check panel type
903 * the panel type must exact match board panel type, this is compatibility check,
904 * if couldn't find the exact match from DTB, will exact match 0x0.
905 */
906 if (!platform_dt_absolute_compat_match(dt_list, DTB_PANEL_TYPE))
907 return NULL;
908
909 /* check boot device subtype
910 * the boot device subtype must exact match board boot device subtype, this is compatibility check,
911 * if couldn't find the exact match from DTB, will exact match 0x0.
912 */
913 if (!platform_dt_absolute_compat_match(dt_list, DTB_BOOT_DEVICE))
914 return NULL;
915
Lijuan Gao9f152862014-08-18 13:45:24 +0800916 /* check soc version
917 * the suitable soc version must less than or equal to board soc version
918 */
919 if (!update_dtb_entry_node(dt_list, DTB_SOC))
920 return NULL;
921
922 /*check major and minor version
923 * the suitable major&minor version must less than or equal to board major&minor version
924 */
925 if (!update_dtb_entry_node(dt_list, DTB_MAJOR_MINOR))
926 return NULL;
927
928 /*check pmic info
929 * the suitable pmic major&minor info must less than or equal to board pmic major&minor version
930 */
931 if (!update_dtb_entry_node(dt_list, DTB_PMIC0))
932 return NULL;
933 if (!update_dtb_entry_node(dt_list, DTB_PMIC1))
934 return NULL;
935 if (!update_dtb_entry_node(dt_list, DTB_PMIC2))
936 return NULL;
937 if (!update_dtb_entry_node(dt_list, DTB_PMIC3))
938 return NULL;
939
940 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
941 if (!dt_node_tmp1) {
942 dprintf(CRITICAL, "ERROR: Couldn't find the suitable DTB!\n");
943 return NULL;
944 }
945 if (dt_node_tmp1->dt_entry_m)
946 return dt_node_tmp1->dt_entry_m;
947 }
948
949 return NULL;
950}
951
952/* Function to obtain the index information for the correct device tree
953 * based on the platform data.
954 * If a matching device tree is found, the information is returned in the
955 * "dt_entry_info" out parameter and a function value of 0 is returned, otherwise
956 * a non-zero function value is returned.
957 */
958int dev_tree_get_entry_info(struct dt_table *table, struct dt_entry *dt_entry_info)
Maria Yuca51ee22013-06-27 21:45:24 +0800959{
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700960 uint32_t i;
Lijuan Gao9f152862014-08-18 13:45:24 +0800961 unsigned char *table_ptr = NULL;
Joel Kingaa335dc2013-06-03 16:11:08 -0700962 struct dt_entry dt_entry_buf_1;
Lijuan Gao9f152862014-08-18 13:45:24 +0800963 struct dt_entry *cur_dt_entry = NULL;
964 struct dt_entry *best_match_dt_entry = NULL;
965 struct dt_entry_v1 *dt_entry_v1 = NULL;
966 struct dt_entry_v2 *dt_entry_v2 = NULL;
967 struct dt_entry_node *dt_entry_queue = NULL;
968 struct dt_entry_node *dt_node_tmp1 = NULL;
969 struct dt_entry_node *dt_node_tmp2 = NULL;
Maria Yu2e2d2c22013-07-03 19:20:33 +0800970 uint32_t found = 0;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700971
Joel Kingaa335dc2013-06-03 16:11:08 -0700972 if (!dt_entry_info) {
973 dprintf(CRITICAL, "ERROR: Bad parameter passed to %s \n",
974 __func__);
975 return -1;
976 }
977
978 table_ptr = (unsigned char *)table + DEV_TREE_HEADER_SIZE;
979 cur_dt_entry = &dt_entry_buf_1;
980 best_match_dt_entry = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800981 dt_entry_queue = (struct dt_entry_node *)
982 malloc(sizeof(struct dt_entry_node));
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700983
Lijuan Gao9f152862014-08-18 13:45:24 +0800984 if (!dt_entry_queue) {
985 dprintf(CRITICAL, "Out of memory\n");
986 return -1;
987 }
988
989 list_initialize(&dt_entry_queue->node);
990 dprintf(INFO, "DTB Total entry: %d, DTB version: %d\n", table->num_entries, table->version);
Maria Yu2e2d2c22013-07-03 19:20:33 +0800991 for(i = 0; found == 0 && i < table->num_entries; i++)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700992 {
Joel Kingaa335dc2013-06-03 16:11:08 -0700993 memset(cur_dt_entry, 0, sizeof(struct dt_entry));
994 switch(table->version) {
995 case DEV_TREE_VERSION_V1:
996 dt_entry_v1 = (struct dt_entry_v1 *)table_ptr;
997 cur_dt_entry->platform_id = dt_entry_v1->platform_id;
998 cur_dt_entry->variant_id = dt_entry_v1->variant_id;
999 cur_dt_entry->soc_rev = dt_entry_v1->soc_rev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001000 cur_dt_entry->board_hw_subtype = (dt_entry_v1->variant_id >> 0x18);
1001 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
1002 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
1003 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
1004 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
Joel Kingaa335dc2013-06-03 16:11:08 -07001005 cur_dt_entry->offset = dt_entry_v1->offset;
1006 cur_dt_entry->size = dt_entry_v1->size;
1007 table_ptr += sizeof(struct dt_entry_v1);
1008 break;
1009 case DEV_TREE_VERSION_V2:
Lijuan Gao9f152862014-08-18 13:45:24 +08001010 dt_entry_v2 = (struct dt_entry_v2*)table_ptr;
1011 cur_dt_entry->platform_id = dt_entry_v2->platform_id;
1012 cur_dt_entry->variant_id = dt_entry_v2->variant_id;
1013 cur_dt_entry->soc_rev = dt_entry_v2->soc_rev;
1014 /* For V2 version of DTBs we have platform version field as part
1015 * of variant ID, in such case the subtype will be mentioned as 0x0
1016 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
1017 * SS -- Subtype
1018 * PM -- Platform major version
1019 * Pm -- Platform minor version
1020 * PH -- Platform hardware CDP/MTP
1021 * In such case to make it compatible with LK algorithm move the subtype
1022 * from variant_id to subtype field
1023 */
1024 if (dt_entry_v2->board_hw_subtype == 0)
1025 cur_dt_entry->board_hw_subtype = (cur_dt_entry->variant_id >> 0x18);
1026 else
1027 cur_dt_entry->board_hw_subtype = dt_entry_v2->board_hw_subtype;
1028 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
1029 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
1030 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
1031 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
1032 cur_dt_entry->offset = dt_entry_v2->offset;
1033 cur_dt_entry->size = dt_entry_v2->size;
1034 table_ptr += sizeof(struct dt_entry_v2);
1035 break;
1036 case DEV_TREE_VERSION_V3:
Joel Kingaa335dc2013-06-03 16:11:08 -07001037 memcpy(cur_dt_entry, (struct dt_entry *)table_ptr,
1038 sizeof(struct dt_entry));
Lijuan Gao9f152862014-08-18 13:45:24 +08001039 /* For V3 version of DTBs we have platform version field as part
1040 * of variant ID, in such case the subtype will be mentioned as 0x0
1041 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
1042 * SS -- Subtype
1043 * PM -- Platform major version
1044 * Pm -- Platform minor version
1045 * PH -- Platform hardware CDP/MTP
1046 * In such case to make it compatible with LK algorithm move the subtype
1047 * from variant_id to subtype field
1048 */
1049 if (cur_dt_entry->board_hw_subtype == 0)
1050 cur_dt_entry->board_hw_subtype = (cur_dt_entry->variant_id >> 0x18);
1051
Joel Kingaa335dc2013-06-03 16:11:08 -07001052 table_ptr += sizeof(struct dt_entry);
1053 break;
1054 default:
1055 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
1056 table->version);
Lijuan Gao9f152862014-08-18 13:45:24 +08001057 free(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001058 return -1;
1059 }
1060
Lijuan Gao9f152862014-08-18 13:45:24 +08001061 /* DTBs must match the platform_id, platform_hw_id, platform_subtype and DDR size.
1062 * The satisfactory DTBs are stored in dt_entry_queue
1063 */
1064 platform_dt_absolute_match(cur_dt_entry, dt_entry_queue);
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -08001065
Lijuan Gao9f152862014-08-18 13:45:24 +08001066 }
1067 best_match_dt_entry = platform_dt_match_best(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001068 if (best_match_dt_entry) {
1069 *dt_entry_info = *best_match_dt_entry;
Maria Yu2e2d2c22013-07-03 19:20:33 +08001070 found = 1;
1071 }
1072
1073 if (found != 0) {
Sundarajan Srinivasan763c0db2014-05-20 17:08:36 -07001074 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 -07001075 dt_entry_info->platform_id, dt_entry_info->soc_rev,
1076 dt_entry_info->variant_id, dt_entry_info->board_hw_subtype,
Lijuan Gao9f152862014-08-18 13:45:24 +08001077 board_platform_id(), board_soc_version(),
1078 board_target_id(), board_hardware_subtype());
1079 if (dt_entry_info->pmic_rev[0] == 0 && dt_entry_info->pmic_rev[0] == 0 &&
1080 dt_entry_info->pmic_rev[0] == 0 && dt_entry_info->pmic_rev[0] == 0) {
1081 dprintf(SPEW, "No maintain pmic info in DTB, device pmic info is 0x%0x/0x%x/0x%x/0x%0x\n",
1082 board_pmic_target(0), board_pmic_target(1),
1083 board_pmic_target(2), board_pmic_target(3));
1084 } else {
1085 dprintf(INFO, "Using pmic info 0x%0x/0x%x/0x%x/0x%0x for device 0x%0x/0x%x/0x%x/0x%0x\n",
1086 dt_entry_info->pmic_rev[0], dt_entry_info->pmic_rev[1],
1087 dt_entry_info->pmic_rev[2], dt_entry_info->pmic_rev[3],
1088 board_pmic_target(0), board_pmic_target(1),
1089 board_pmic_target(2), board_pmic_target(3));
1090 }
Joel Kingaa335dc2013-06-03 16:11:08 -07001091 return 0;
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -08001092 }
1093
Lijuan Gao9f152862014-08-18 13:45:24 +08001094 dprintf(CRITICAL, "ERROR: Unable to find suitable device tree for device (%u/0x%08x/0x%08x/%u)\n",
1095 board_platform_id(), board_soc_version(),
1096 board_target_id(), board_hardware_subtype());
1097
1098 list_for_every_entry(&dt_entry_queue->node, dt_node_tmp1, dt_node, node) {
1099 /* free node memory */
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001100 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001101 dt_entry_list_delete(dt_node_tmp1);
1102 dt_node_tmp1 = dt_node_tmp2;
1103 }
1104 free(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001105 return -1;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001106}
1107
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001108/* Function to add the first RAM partition info to the device tree.
1109 * Note: The function replaces the reg property in the "/memory" node
1110 * with the addr and size provided.
1111 */
1112int dev_tree_add_first_mem_info(uint32_t *fdt, uint32_t offset, uint32_t addr, uint32_t size)
1113{
1114 int ret;
1115
1116 ret = fdt_setprop_u32(fdt, offset, "reg", addr);
1117
1118 if (ret)
1119 {
1120 dprintf(CRITICAL, "Failed to add the memory information addr: %d\n",
1121 ret);
1122 }
1123
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001124 ret = fdt_appendprop_u32(fdt, offset, "reg", size);
1125
1126 if (ret)
1127 {
1128 dprintf(CRITICAL, "Failed to add the memory information size: %d\n",
1129 ret);
1130 }
1131
1132 return ret;
1133}
1134
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001135static 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 -07001136{
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001137 int len;
1138 uint32_t *valp;
1139 int ret;
1140 uint32_t offset;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001141
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001142 mem_node->offset = mem_node_offset;
1143
1144 /* Get offset of the root node */
1145 ret = fdt_path_offset(fdt, "/");
1146 if (ret < 0)
1147 {
1148 dprintf(CRITICAL, "Could not find memory node.\n");
1149 return ret;
1150 }
1151
1152 offset = ret;
1153
1154 /* Find the #address-cells size. */
1155 valp = (uint32_t*)fdt_getprop(fdt, offset, "#address-cells", &len);
Lijuan Gaoae0927b2014-07-18 17:16:16 +08001156 if (len <= 0 || !valp)
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001157 {
1158 if (len == -FDT_ERR_NOTFOUND)
1159 {
1160 /* Property not found.
1161 * Assume standard sizes.
1162 */
1163 mem_node->addr_cell_size = 2;
1164 dprintf(CRITICAL, "Using default #addr_cell_size: %u\n", mem_node->addr_cell_size);
1165 }
1166 else
1167 {
1168 dprintf(CRITICAL, "Error finding the #address-cells property\n");
1169 return len;
1170 }
1171 }
1172 else
1173 mem_node->addr_cell_size = fdt32_to_cpu(*valp);
1174
1175 /* Find the #size-cells size. */
1176 valp = (uint32_t*)fdt_getprop(fdt, offset, "#size-cells", &len);
Lijuan Gaoae0927b2014-07-18 17:16:16 +08001177 if (len <= 0 || !valp)
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001178 {
1179 if (len == -FDT_ERR_NOTFOUND)
1180 {
1181 /* Property not found.
1182 * Assume standard sizes.
1183 */
1184 mem_node->size_cell_size = 1;
1185 dprintf(CRITICAL, "Using default #size_cell_size: %u\n", mem_node->size_cell_size);
1186 }
1187 else
1188 {
1189 dprintf(CRITICAL, "Error finding the #size-cells property\n");
1190 return len;
1191 }
1192 }
1193 else
1194 mem_node->size_cell_size = fdt32_to_cpu(*valp);
1195
1196 return 0;
1197}
1198
1199static void dev_tree_update_memory_node(uint32_t offset)
1200{
1201 mem_node.offset = offset;
1202 mem_node.addr_cell_size = 1;
1203 mem_node.size_cell_size = 1;
1204}
1205
1206/* Function to add the subsequent RAM partition info to the device tree. */
1207int dev_tree_add_mem_info(void *fdt, uint32_t offset, uint64_t addr, uint64_t size)
1208{
1209 int ret = 0;
1210
1211 if(smem_get_ram_ptable_version() >= 1)
1212 {
1213 ret = dev_tree_query_memory_cell_sizes(fdt, &mem_node, offset);
1214 if (ret < 0)
1215 {
1216 dprintf(CRITICAL, "Could not find #address-cells and #size-cells properties: ret %d\n", ret);
1217 return ret;
1218 }
1219
1220 }
1221 else
1222 {
1223 dev_tree_update_memory_node(offset);
1224 }
1225
1226 if (!(mem_node.mem_info_cnt))
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001227 {
1228 /* Replace any other reg prop in the memory node. */
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001229
1230 /* cell_size is the number of 32 bit words used to represent an address/length in the device tree.
1231 * memory node in DT can be either 32-bit(cell-size = 1) or 64-bit(cell-size = 2).So when updating
1232 * the memory node in the device tree, we write one word or two words based on cell_size = 1 or 2.
1233 */
1234
1235 if(mem_node.addr_cell_size == 2)
1236 {
1237 ret = fdt_setprop_u32(fdt, mem_node.offset, "reg", addr >> 32);
1238 if(ret)
1239 {
1240 dprintf(CRITICAL, "ERROR: Could not set prop reg for memory node\n");
1241 return ret;
1242 }
1243
1244 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1245 if(ret)
1246 {
1247 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1248 return ret;
1249 }
1250 }
1251 else
1252 {
1253 ret = fdt_setprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1254 if(ret)
1255 {
1256 dprintf(CRITICAL, "ERROR: Could not set prop reg for memory node\n");
1257 return ret;
1258 }
1259 }
1260
1261 mem_node.mem_info_cnt = 1;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001262 }
1263 else
1264 {
1265 /* Append the mem info to the reg prop for subsequent nodes. */
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001266 if(mem_node.addr_cell_size == 2)
1267 {
1268 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", addr >> 32);
1269 if(ret)
1270 {
1271 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1272 return ret;
1273 }
1274 }
1275
1276 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1277 if(ret)
1278 {
1279 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1280 return ret;
1281 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001282 }
1283
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001284 if(mem_node.size_cell_size == 2)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001285 {
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001286 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", size>>32);
1287 if(ret)
1288 {
1289 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1290 return ret;
1291 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001292 }
1293
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001294 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)size);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001295
1296 if (ret)
1297 {
1298 dprintf(CRITICAL, "Failed to add the memory information size: %d\n",
1299 ret);
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001300 return ret;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001301 }
1302
1303 return ret;
1304}
1305
1306/* Top level function that updates the device tree. */
1307int update_device_tree(void *fdt, const char *cmdline,
1308 void *ramdisk, uint32_t ramdisk_size)
1309{
1310 int ret = 0;
1311 uint32_t offset;
lijuangc76a7632017-12-07 14:37:56 +08001312#if ENABLE_KASLRSEED_SUPPORT
1313 uintptr_t kaslrseed;
1314#endif
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001315
1316 /* Check the device tree header */
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +05301317 ret = fdt_check_header(fdt) || fdt_check_header_ext(fdt);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001318 if (ret)
1319 {
1320 dprintf(CRITICAL, "Invalid device tree header \n");
1321 return ret;
1322 }
1323
P.V. Phani Kumar9cd95102016-03-09 12:35:23 +05301324 if (check_aboot_addr_range_overlap((uint32_t)fdt,
lijuang365c6f92017-11-14 17:09:05 +08001325 (fdt_totalsize(fdt) + DTB_PAD_SIZE + strlen(cmdline)))) {
P.V. Phani Kumar9cd95102016-03-09 12:35:23 +05301326 dprintf(CRITICAL, "Error: Fdt addresses overlap with aboot addresses.\n");
1327 return ret;
1328 }
1329
Deepa Dinamani1c970732013-04-19 14:23:01 -07001330 /* Add padding to make space for new nodes and properties. */
lijuang365c6f92017-11-14 17:09:05 +08001331 ret = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + DTB_PAD_SIZE + strlen(cmdline));
Deepa Dinamani1c970732013-04-19 14:23:01 -07001332 if (ret!= 0)
1333 {
1334 dprintf(CRITICAL, "Failed to move/resize dtb buffer: %d\n", ret);
1335 return ret;
1336 }
1337
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001338 /* Get offset of the memory node */
1339 ret = fdt_path_offset(fdt, "/memory");
1340 if (ret < 0)
1341 {
1342 dprintf(CRITICAL, "Could not find memory node.\n");
1343 return ret;
1344 }
1345
1346 offset = ret;
1347
1348 ret = target_dev_tree_mem(fdt, offset);
1349 if(ret)
1350 {
1351 dprintf(CRITICAL, "ERROR: Cannot update memory node\n");
1352 return ret;
1353 }
1354
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001355 /* Get offset of the chosen node */
1356 ret = fdt_path_offset(fdt, "/chosen");
1357 if (ret < 0)
1358 {
1359 dprintf(CRITICAL, "Could not find chosen node.\n");
1360 return ret;
1361 }
1362
1363 offset = ret;
Maria Yuabde9542014-07-07 14:49:34 +08001364 if (cmdline)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001365 {
Maria Yuabde9542014-07-07 14:49:34 +08001366 /* Adding the cmdline to the chosen node */
1367 ret = fdt_appendprop_string(fdt, offset, (const char*)"bootargs", (const void*)cmdline);
1368 if (ret)
1369 {
1370 dprintf(CRITICAL, "ERROR: Cannot update chosen node [bootargs]\n");
1371 return ret;
1372 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001373 }
1374
lijuangc76a7632017-12-07 14:37:56 +08001375#if ENABLE_KASLRSEED_SUPPORT
1376 if (!scm_random(&kaslrseed, sizeof(kaslrseed))) {
1377 /* Adding Kaslr Seed to the chosen node */
1378 ret = fdt_appendprop_u64 (fdt, offset, (const char *)"kaslr-seed", (uint64_t)kaslrseed);
1379 if (ret)
1380 dprintf(CRITICAL, "ERROR: Cannot update chosen node [kaslr-seed] - 0x%x\n", ret);
1381 else
1382 dprintf(CRITICAL, "kaslr-Seed is added to chosen node\n");
1383 } else {
1384 dprintf(CRITICAL, "ERROR: Cannot generate Kaslr Seed\n");
1385 }
1386#endif
1387
Joonwoo Parka5b5f492014-02-13 18:24:48 -08001388 if (ramdisk_size) {
1389 /* Adding the initrd-start to the chosen node */
1390 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-start",
1391 (uint32_t)ramdisk);
1392 if (ret)
1393 {
1394 dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-start]\n");
1395 return ret;
1396 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001397
Joonwoo Parka5b5f492014-02-13 18:24:48 -08001398 /* Adding the initrd-end to the chosen node */
1399 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-end",
1400 ((uint32_t)ramdisk + ramdisk_size));
1401 if (ret)
1402 {
1403 dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-end]\n");
1404 return ret;
1405 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001406 }
1407
Kishor PK536904a2017-07-13 17:18:59 +05301408#if ENABLE_BOOTDEVICE_MOUNT
1409 /* Update fstab node */
1410 dprintf(SPEW, "Start of fstab node update:%zu ms\n", platform_get_sclk_count());
1411 if (update_fstab_node(fdt) != 0) {
1412 dprintf(CRITICAL, "ERROR: Cannot update fstab node\n");
1413 return ret;
1414 }
1415 dprintf(SPEW, "End of fstab node update:%zu ms\n", platform_get_sclk_count());
1416#endif
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001417 fdt_pack(fdt);
1418
Channagoud Kadabiffaea422014-12-05 15:45:41 -08001419#if ENABLE_PARTIAL_GOODS_SUPPORT
1420 update_partial_goods_dtb_nodes(fdt);
1421#endif
1422
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001423 return ret;
1424}
Kishor PK536904a2017-07-13 17:18:59 +05301425
1426#if ENABLE_BOOTDEVICE_MOUNT
1427/*Update device tree for fstab node */
1428static int update_fstab_node(void *fdt)
1429{
1430 int ret = 0;
1431 int str_len = 0;
1432 int parent_offset = 0;
1433 int subnode_offset = 0;
1434 int prop_length = 0;
1435 int prefix_string_len = 0;
1436 char *node_name = NULL;
1437 char *boot_dev_buf = NULL;
1438 char *new_str = NULL;
1439 char *prefix_str = NULL;
1440 char *suffix_str = NULL;
1441 const struct fdt_property *prop = NULL;
1442
1443 /* Find the parent node */
1444 parent_offset = fdt_path_offset(fdt, fstab_table.parent_node);
1445 if (parent_offset < 0) {
1446 dprintf(CRITICAL, "Failed to get parent node: fstab error: %d\n", parent_offset);
1447 return -1;
1448 }
1449 dprintf(SPEW, "Node: %s found.\n", fdt_get_name(fdt, parent_offset, NULL));
1450
1451 /* Get boot device type */
1452 boot_dev_buf = (char *) malloc(sizeof(char) * BOOT_DEV_MAX_LEN);
1453 if (!boot_dev_buf) {
1454 dprintf(CRITICAL, "Failed to allocate memory for boot device\n");
1455 return -1;
1456 }
1457
1458 new_str = (char *) malloc(sizeof(char) * NODE_PROPERTY_MAX_LEN);
1459 if (!new_str) {
1460 dprintf(CRITICAL, "Failed to allocate memory for node property string\n");
1461 return -1;
1462 }
1463
1464
1465 platform_boot_dev_cmdline(boot_dev_buf);
1466
1467 /* Get properties of all sub nodes */
1468 for (subnode_offset = fdt_first_subnode(fdt, parent_offset); subnode_offset >= 0; subnode_offset = fdt_next_subnode(fdt, subnode_offset)) {
1469 prop = fdt_get_property(fdt, subnode_offset, fstab_table.node_prop, &prop_length);
1470 node_name = (char *)(uintptr_t)fdt_get_name(fdt, subnode_offset, NULL);
1471 if (!prop) {
1472 dprintf(CRITICAL, "Property:%s is not found for sub node:%s\n", fstab_table.node_prop, node_name);
1473 } else {
1474 dprintf(CRITICAL, "Property:%s found for sub node:%s\tproperty:%s\n", fstab_table.node_prop, node_name, prop->data);
1475 /* Pointer to fdt 'dev' property string that needs to update based on the 'androidboot.bootdevice' */
1476 memset(new_str, 0, NODE_PROPERTY_MAX_LEN);
1477 prefix_str = (char *)prop->data;
1478 if (strlen(prefix_str) > NODE_PROPERTY_MAX_LEN) {
1479 dprintf(CRITICAL, "Property string length is greater than node property max length\n");
1480 continue;
1481 }
1482 suffix_str = strstr(prefix_str, fstab_table.device_path_id);
1483 if (!suffix_str) {
1484 dprintf(CRITICAL, "Property is not proper to update\n");
1485 continue;
1486 }
1487 suffix_str += strlen(fstab_table.device_path_id);
1488 prefix_string_len = strlen(prefix_str) - (strlen(suffix_str) - 1);
1489 suffix_str = strstr((suffix_str + 1), "/");
1490 str_len = strlcpy(new_str, prefix_str, prefix_string_len);
1491 if (!str_len) {
1492 dprintf(CRITICAL, "Property length is not proper to update\n");
1493 continue;
1494 }
1495 str_len = strlcat(new_str, boot_dev_buf, strlen(prefix_str));
1496 if (!str_len) {
1497 dprintf(CRITICAL, "Property length is not proper to update\n");
1498 continue;
1499 }
1500 str_len = strlcat(new_str, suffix_str, strlen(prefix_str));
1501 if (!str_len) {
1502 dprintf(CRITICAL, "Property length is not proper to update\n");
1503 continue;
1504 }
1505 /* Update the new property in the memory */
1506 memscpy(prefix_str, strlen(prefix_str), new_str, strlen(new_str) + 1);
1507 /* Update the property with new value */
1508 ret = fdt_setprop(fdt, subnode_offset, fstab_table.node_prop, (const void *)prefix_str, strlen(prefix_str) + 1);
1509 if(ret) {
1510 dprintf(CRITICAL, "Failed to update the node with new property\n");
1511 continue;
1512 }
1513 dprintf(CRITICAL, "Updated %s with new property %s\n", node_name, prop->data);
1514 }
1515 }
1516 if (boot_dev_buf)
1517 free(boot_dev_buf);
1518 if (new_str)
1519 free(new_str);
1520 return ret;
1521}
1522#endif