blob: 11f961625d7cb5f95f61d7478a5579f3d15b67ad [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>
44
45#define BOOT_DEV_MAX_LEN 64
46#define NODE_PROPERTY_MAX_LEN 64
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -070047
Joel Kingaa335dc2013-06-03 16:11:08 -070048struct dt_entry_v1
49{
50 uint32_t platform_id;
51 uint32_t variant_id;
52 uint32_t soc_rev;
53 uint32_t offset;
54 uint32_t size;
55};
56
Kishor PK536904a2017-07-13 17:18:59 +053057#if ENABLE_BOOTDEVICE_MOUNT
58/* Look up table for fstab node */
59struct fstab_node
60{
61 const char *parent_node;
62 const char *node_prop;
63 const char *device_path_id;
64};
65
66static struct fstab_node fstab_table =
67{
68 "/firmware/android/fstab", "dev", "/soc/"
69};
70#endif
71
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -070072static struct dt_mem_node_info mem_node;
Lijuan Gao9f152862014-08-18 13:45:24 +080073static int platform_dt_absolute_match(struct dt_entry *cur_dt_entry, struct dt_entry_node *dt_list);
74static struct dt_entry *platform_dt_match_best(struct dt_entry_node *dt_list);
75static int update_dtb_entry_node(struct dt_entry_node *dt_list, uint32_t dtb_info);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -070076extern int target_is_emmc_boot(void);
77extern uint32_t target_dev_tree_mem(void *fdt, uint32_t memory_node_offset);
Kishor PK536904a2017-07-13 17:18:59 +053078static int update_fstab_node(void *fdt);
79
Deepa Dinamanic55f01b2013-05-30 14:05:56 -070080/* TODO: This function needs to be moved to target layer to check violations
81 * against all the other regions as well.
82 */
Vijay Kumar Pendoti9c002ad2016-03-09 13:52:45 +053083extern int check_aboot_addr_range_overlap(uintptr_t start, uint32_t size);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -070084
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +053085int fdt_check_header_ext(const void *fdt)
86{
87 uintptr_t fdt_start, fdt_end;
88 fdt_start = (uintptr_t)fdt;
89 if(fdt_start + fdt_totalsize(fdt) < fdt_start)
90 {
91 dprintf(CRITICAL,"Integer over in fdt header %s\t%d",__func__,__LINE__);
92 return FDT_ERR_BADOFFSET;
93 }
94 fdt_end = fdt_start + fdt_totalsize(fdt);
95
96 if (((uint64_t)fdt_start + (uint64_t)fdt_off_dt_struct(fdt) + (uint64_t)fdt_size_dt_struct(fdt)) > UINT_MAX)
97 return FDT_ERR_BADOFFSET;
98
99 if ((fdt_start + fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt)) > fdt_end)
100 return FDT_ERR_BADOFFSET;
101
102 if (((uint64_t)fdt_start + (uint64_t)fdt_off_dt_strings(fdt) + (uint64_t)fdt_size_dt_strings(fdt)) > UINT_MAX)
103 return FDT_ERR_BADOFFSET;
104
105 if ((fdt_start + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)) > fdt_end)
106 return FDT_ERR_BADOFFSET;
107
108 return 0;
109}
110
Shashank Mittalc0f10282013-07-15 14:53:31 -0700111/* Returns soc version if platform id and hardware id matches
112 otherwise return 0xFFFFFFFF */
113#define INVALID_SOC_REV_ID 0XFFFFFFFF
Lijuan Gao9f152862014-08-18 13:45:24 +0800114
115/* Add function to allocate dt entry list, used for recording
116* the entry which conform to platform_dt_absolute_match()
117*/
118static struct dt_entry_node *dt_entry_list_init(void)
119{
120 struct dt_entry_node *dt_node_member = NULL;
121
122 dt_node_member = (struct dt_entry_node *)
123 malloc(sizeof(struct dt_entry_node));
124
125 ASSERT(dt_node_member);
126
127 list_clear_node(&dt_node_member->node);
128 dt_node_member->dt_entry_m = (struct dt_entry *)
129 malloc(sizeof(struct dt_entry));
130 ASSERT(dt_node_member->dt_entry_m);
131
132 memset(dt_node_member->dt_entry_m ,0 ,sizeof(struct dt_entry));
133 return dt_node_member;
134}
135
136static void insert_dt_entry_in_queue(struct dt_entry_node *dt_list, struct dt_entry_node *dt_node_member)
137{
138 list_add_tail(&dt_list->node, &dt_node_member->node);
139}
140
141static void dt_entry_list_delete(struct dt_entry_node *dt_node_member)
142{
143 if (list_in_list(&dt_node_member->node)) {
144 list_delete(&dt_node_member->node);
145 free(dt_node_member->dt_entry_m);
146 free(dt_node_member);
147 }
148}
149
150static int dev_tree_compatible(void *dtb, uint32_t dtb_size, struct dt_entry_node *dtb_list)
Dima Zavinc46f8382013-05-03 12:23:06 -0700151{
152 int root_offset;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700153 const void *prop = NULL;
154 const char *plat_prop = NULL;
155 const char *board_prop = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800156 const char *pmic_prop = NULL;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700157 char *model = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800158 struct dt_entry *cur_dt_entry;
159 struct dt_entry *dt_entry_array = NULL;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700160 struct board_id *board_data = NULL;
161 struct plat_id *platform_data = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800162 struct pmic_id *pmic_data = NULL;
Dima Zavinc46f8382013-05-03 12:23:06 -0700163 int len;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700164 int len_board_id;
165 int len_plat_id;
166 int min_plat_id_len = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800167 int len_pmic_id;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700168 uint32_t dtb_ver;
169 uint32_t num_entries = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800170 uint32_t i, j, k, n;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700171 uint32_t msm_data_count;
172 uint32_t board_data_count;
Lijuan Gao9f152862014-08-18 13:45:24 +0800173 uint32_t pmic_data_count;
Dima Zavinc46f8382013-05-03 12:23:06 -0700174
175 root_offset = fdt_path_offset(dtb, "/");
176 if (root_offset < 0)
177 return false;
178
179 prop = fdt_getprop(dtb, root_offset, "model", &len);
180 if (prop && len > 0) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700181 model = (char *) malloc(sizeof(char) * len);
182 ASSERT(model);
183 strlcpy(model, prop, len);
Dima Zavinc46f8382013-05-03 12:23:06 -0700184 } else {
vijay kumar89d36d82014-06-30 19:32:18 +0530185 dprintf(INFO, "model does not exist in device tree\n");
Dima Zavinc46f8382013-05-03 12:23:06 -0700186 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800187 /* Find the pmic-id prop from DTB , if pmic-id is present then
188 * the DTB is version 3, otherwise find the board-id prop from DTB ,
189 * if board-id is present then the DTB is version 2 */
190 pmic_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,pmic-id", &len_pmic_id);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700191 board_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,board-id", &len_board_id);
Lijuan Gao9f152862014-08-18 13:45:24 +0800192 if (pmic_prop && (len_pmic_id > 0) && board_prop && (len_board_id > 0)) {
193 if ((len_pmic_id % PMIC_ID_SIZE) || (len_board_id % BOARD_ID_SIZE))
194 {
195 dprintf(CRITICAL, "qcom,pmic-id(%d) or qcom,board-id(%d) in device tree is not a multiple of (%d %d)\n",
196 len_pmic_id, len_board_id, PMIC_ID_SIZE, BOARD_ID_SIZE);
197 return false;
198 }
199 dtb_ver = DEV_TREE_VERSION_V3;
200 min_plat_id_len = PLAT_ID_SIZE;
201 } else if (board_prop && len_board_id > 0) {
vijay kumar89d36d82014-06-30 19:32:18 +0530202 if (len_board_id % BOARD_ID_SIZE)
203 {
204 dprintf(CRITICAL, "qcom,board-id in device tree is (%d) not a multiple of (%d)\n",
205 len_board_id, BOARD_ID_SIZE);
206 return false;
207 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700208 dtb_ver = DEV_TREE_VERSION_V2;
209 min_plat_id_len = PLAT_ID_SIZE;
Lijuan Gao9f152862014-08-18 13:45:24 +0800210 } else {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700211 dtb_ver = DEV_TREE_VERSION_V1;
212 min_plat_id_len = DT_ENTRY_V1_SIZE;
213 }
214
215 /* Get the msm-id prop from DTB */
216 plat_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,msm-id", &len_plat_id);
217 if (!plat_prop || len_plat_id <= 0) {
Dima Zavinc46f8382013-05-03 12:23:06 -0700218 dprintf(INFO, "qcom,msm-id entry not found\n");
219 return false;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700220 } else if (len_plat_id % min_plat_id_len) {
221 dprintf(INFO, "qcom,msm-id in device tree is (%d) not a multiple of (%d)\n",
222 len_plat_id, min_plat_id_len);
Dima Zavinc46f8382013-05-03 12:23:06 -0700223 return false;
224 }
Dima Zavinc46f8382013-05-03 12:23:06 -0700225
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700226 /*
227 * If DTB version is '1' look for <x y z> pair in the DTB
228 * x: platform_id
229 * y: variant_id
230 * z: SOC rev
231 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800232 if (dtb_ver == DEV_TREE_VERSION_V1) {
233 cur_dt_entry = (struct dt_entry *)
234 malloc(sizeof(struct dt_entry));
Dima Zavinc46f8382013-05-03 12:23:06 -0700235
Lijuan Gao9f152862014-08-18 13:45:24 +0800236 if (!cur_dt_entry) {
237 dprintf(CRITICAL, "Out of memory\n");
238 return false;
239 }
240 memset(cur_dt_entry, 0, sizeof(struct dt_entry));
241
242 while (len_plat_id) {
243 cur_dt_entry->platform_id = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->platform_id);
244 cur_dt_entry->variant_id = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->variant_id);
245 cur_dt_entry->soc_rev = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->soc_rev);
246 cur_dt_entry->board_hw_subtype =
247 fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->variant_id) >> 0x18;
248 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
249 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
250 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
251 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
252 cur_dt_entry->offset = (uint32_t)dtb;
253 cur_dt_entry->size = dtb_size;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700254
255 dprintf(SPEW, "Found an appended flattened device tree (%s - %u %u 0x%x)\n",
Lijuan Gao9f152862014-08-18 13:45:24 +0800256 *model ? model : "unknown",
257 cur_dt_entry->platform_id, cur_dt_entry->variant_id, cur_dt_entry->soc_rev);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700258
Lijuan Gao9f152862014-08-18 13:45:24 +0800259 if (platform_dt_absolute_match(cur_dt_entry, dtb_list)) {
260 dprintf(SPEW, "Device tree exact match the board: <%u %u 0x%x> != <%u %u 0x%x>\n",
261 cur_dt_entry->platform_id,
262 cur_dt_entry->variant_id,
263 cur_dt_entry->soc_rev,
264 board_platform_id(),
265 board_hardware_id(),
266 board_soc_version());
267
268 } else {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700269 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 +0800270 cur_dt_entry->platform_id,
271 cur_dt_entry->variant_id,
272 cur_dt_entry->soc_rev,
273 board_platform_id(),
274 board_hardware_id(),
275 board_soc_version());
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700276 plat_prop += DT_ENTRY_V1_SIZE;
277 len_plat_id -= DT_ENTRY_V1_SIZE;
278 continue;
279 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700280 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800281 free(cur_dt_entry);
282
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700283 }
284 /*
Lijuan Gao9f152862014-08-18 13:45:24 +0800285 * If DTB Version is '3' then we have split DTB with board & msm data & pmic
286 * populated saperately in board-id & msm-id & pmic-id prop respectively.
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700287 * Extract the data & prepare a look up table
288 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800289 else if (dtb_ver == DEV_TREE_VERSION_V2 || dtb_ver == DEV_TREE_VERSION_V3) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700290 board_data_count = (len_board_id / BOARD_ID_SIZE);
291 msm_data_count = (len_plat_id / PLAT_ID_SIZE);
Lijuan Gao9f152862014-08-18 13:45:24 +0800292 /* If dtb version is v2.0, the pmic_data_count will be <= 0 */
293 pmic_data_count = (len_pmic_id / PMIC_ID_SIZE);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700294
Lijuan Gao9f152862014-08-18 13:45:24 +0800295 /* If we are using dtb v3.0, then we have split board, msm & pmic data in the DTB
296 * If we are using dtb v2.0, then we have split board & msmdata in the DTB
297 */
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700298 board_data = (struct board_id *) malloc(sizeof(struct board_id) * (len_board_id / BOARD_ID_SIZE));
299 ASSERT(board_data);
300 platform_data = (struct plat_id *) malloc(sizeof(struct plat_id) * (len_plat_id / PLAT_ID_SIZE));
301 ASSERT(platform_data);
Lijuan Gao9f152862014-08-18 13:45:24 +0800302 if (dtb_ver == DEV_TREE_VERSION_V3) {
303 pmic_data = (struct pmic_id *) malloc(sizeof(struct pmic_id) * (len_pmic_id / PMIC_ID_SIZE));
304 ASSERT(pmic_data);
305 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700306 i = 0;
307
308 /* Extract board data from DTB */
Lijuan Gao9f152862014-08-18 13:45:24 +0800309 for(i = 0 ; i < board_data_count; i++) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700310 board_data[i].variant_id = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id);
311 board_data[i].platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->platform_subtype);
Lijuan Gao9f152862014-08-18 13:45:24 +0800312 /* For V2/V3 version of DTBs we have platform version field as part
313 * of variant ID, in such case the subtype will be mentioned as 0x0
314 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
315 * SS -- Subtype
316 * PM -- Platform major version
317 * Pm -- Platform minor version
318 * PH -- Platform hardware CDP/MTP
319 * In such case to make it compatible with LK algorithm move the subtype
320 * from variant_id to subtype field
321 */
322 if (board_data[i].platform_subtype == 0)
323 board_data[i].platform_subtype =
324 fdt32_to_cpu(((struct board_id *)board_prop)->variant_id) >> 0x18;
325
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700326 len_board_id -= sizeof(struct board_id);
327 board_prop += sizeof(struct board_id);
328 }
329
330 /* Extract platform data from DTB */
Lijuan Gao9f152862014-08-18 13:45:24 +0800331 for(i = 0 ; i < msm_data_count; i++) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700332 platform_data[i].platform_id = fdt32_to_cpu(((struct plat_id *)plat_prop)->platform_id);
333 platform_data[i].soc_rev = fdt32_to_cpu(((struct plat_id *)plat_prop)->soc_rev);
334 len_plat_id -= sizeof(struct plat_id);
335 plat_prop += sizeof(struct plat_id);
336 }
337
Lijuan Gao9f152862014-08-18 13:45:24 +0800338 if (dtb_ver == DEV_TREE_VERSION_V3 && pmic_prop) {
339 /* Extract pmic data from DTB */
340 for(i = 0 ; i < pmic_data_count; i++) {
341 pmic_data[i].pmic_version[0]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[0]);
342 pmic_data[i].pmic_version[1]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[1]);
343 pmic_data[i].pmic_version[2]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[2]);
344 pmic_data[i].pmic_version[3]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[3]);
345 len_pmic_id -= sizeof(struct pmic_id);
346 pmic_prop += sizeof(struct pmic_id);
347 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700348
Lijuan Gao9f152862014-08-18 13:45:24 +0800349 /* We need to merge board & platform data into dt entry structure */
350 num_entries = msm_data_count * board_data_count * pmic_data_count;
351 } else {
352 /* We need to merge board & platform data into dt entry structure */
353 num_entries = msm_data_count * board_data_count;
354 }
vijay kumar89d36d82014-06-30 19:32:18 +0530355
Lijuan Gao9f152862014-08-18 13:45:24 +0800356 if ((((uint64_t)msm_data_count * (uint64_t)board_data_count * (uint64_t)pmic_data_count) !=
357 msm_data_count * board_data_count * pmic_data_count) ||
358 (((uint64_t)msm_data_count * (uint64_t)board_data_count) != msm_data_count * board_data_count)) {
359
360 free(board_data);
361 free(platform_data);
362 if (pmic_data)
363 free(pmic_data);
364 if (model)
365 free(model);
366 return false;
367 }
368
369 dt_entry_array = (struct dt_entry*) malloc(sizeof(struct dt_entry) * num_entries);
370 ASSERT(dt_entry_array);
371
372 /* If we have '<X>; <Y>; <Z>' as platform data & '<A>; <B>; <C>' as board data.
373 * Then dt entry should look like
374 * <X ,A >;<X, B>;<X, C>;
375 * <Y ,A >;<Y, B>;<Y, C>;
376 * <Z ,A >;<Z, B>;<Z, C>;
377 */
378 i = 0;
379 k = 0;
380 n = 0;
381 for (i = 0; i < msm_data_count; i++) {
382 for (j = 0; j < board_data_count; j++) {
383 if (dtb_ver == DEV_TREE_VERSION_V3 && pmic_prop) {
384 for (n = 0; n < pmic_data_count; n++) {
385 dt_entry_array[k].platform_id = platform_data[i].platform_id;
386 dt_entry_array[k].soc_rev = platform_data[i].soc_rev;
387 dt_entry_array[k].variant_id = board_data[j].variant_id;
388 dt_entry_array[k].board_hw_subtype = board_data[j].platform_subtype;
389 dt_entry_array[k].pmic_rev[0]= pmic_data[n].pmic_version[0];
390 dt_entry_array[k].pmic_rev[1]= pmic_data[n].pmic_version[1];
391 dt_entry_array[k].pmic_rev[2]= pmic_data[n].pmic_version[2];
392 dt_entry_array[k].pmic_rev[3]= pmic_data[n].pmic_version[3];
393 dt_entry_array[k].offset = (uint32_t)dtb;
394 dt_entry_array[k].size = dtb_size;
395 k++;
396 }
397
398 } else {
399 dt_entry_array[k].platform_id = platform_data[i].platform_id;
400 dt_entry_array[k].soc_rev = platform_data[i].soc_rev;
401 dt_entry_array[k].variant_id = board_data[j].variant_id;
402 dt_entry_array[k].board_hw_subtype = board_data[j].platform_subtype;
403 dt_entry_array[k].pmic_rev[0]= board_pmic_target(0);
404 dt_entry_array[k].pmic_rev[1]= board_pmic_target(1);
405 dt_entry_array[k].pmic_rev[2]= board_pmic_target(2);
406 dt_entry_array[k].pmic_rev[3]= board_pmic_target(3);
407 dt_entry_array[k].offset = (uint32_t)dtb;
408 dt_entry_array[k].size = dtb_size;
vijay kumar89d36d82014-06-30 19:32:18 +0530409 k++;
410 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700411 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800412 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700413
Lijuan Gao9f152862014-08-18 13:45:24 +0800414 for (i=0 ;i < num_entries; i++) {
415 dprintf(SPEW, "Found an appended flattened device tree (%s - %u %u %u 0x%x)\n",
416 *model ? model : "unknown",
417 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 +0530418
Lijuan Gao9f152862014-08-18 13:45:24 +0800419 if (platform_dt_absolute_match(&(dt_entry_array[i]), dtb_list)) {
420 dprintf(SPEW, "Device tree exact match the board: <%u %u %u 0x%x> == <%u %u %u 0x%x>\n",
421 dt_entry_array[i].platform_id,
422 dt_entry_array[i].variant_id,
423 dt_entry_array[i].soc_rev,
424 dt_entry_array[i].board_hw_subtype,
425 board_platform_id(),
426 board_hardware_id(),
427 board_hardware_subtype(),
428 board_soc_version());
vijay kumar89d36d82014-06-30 19:32:18 +0530429
Lijuan Gao9f152862014-08-18 13:45:24 +0800430 } else {
431 dprintf(SPEW, "Device tree's msm_id doesn't match the board: <%u %u %u 0x%x> != <%u %u %u 0x%x>\n",
432 dt_entry_array[i].platform_id,
433 dt_entry_array[i].variant_id,
434 dt_entry_array[i].soc_rev,
435 dt_entry_array[i].board_hw_subtype,
436 board_platform_id(),
437 board_hardware_id(),
438 board_hardware_subtype(),
439 board_soc_version());
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700440 }
441 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800442
443 free(board_data);
444 free(platform_data);
445 if (pmic_data)
446 free(pmic_data);
447 free(dt_entry_array);
Dima Zavinc46f8382013-05-03 12:23:06 -0700448 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800449 if (model)
vijay kumar89d36d82014-06-30 19:32:18 +0530450 free(model);
Lijuan Gao9f152862014-08-18 13:45:24 +0800451 return true;
Dima Zavinc46f8382013-05-03 12:23:06 -0700452}
453
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800454/*
Dima Zavin77e41f32013-03-06 16:10:43 -0800455 * Will relocate the DTB to the tags addr if the device tree is found and return
456 * its address
457 *
458 * Arguments: kernel - Start address of the kernel loaded in RAM
459 * tags - Start address of the tags loaded in RAM
Channagoud Kadabi704cd562013-04-25 15:19:59 -0700460 * kernel_size - Size of the kernel in bytes
461 *
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800462 * Return Value: DTB address : If appended device tree is found
Dima Zavin77e41f32013-03-06 16:10:43 -0800463 * 'NULL' : Otherwise
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800464 */
Matthew Qinbb7923d2015-02-09 10:56:09 +0800465void *dev_tree_appended(void *kernel, uint32_t kernel_size, uint32_t dtb_offset, void *tags)
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800466{
Parth Dixit97e47bb2016-03-07 17:20:44 +0530467 uintptr_t kernel_end = (uintptr_t)kernel + kernel_size;
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800468 uint32_t app_dtb_offset = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800469 void *dtb = NULL;
Shashank Mittalc0f10282013-07-15 14:53:31 -0700470 void *bestmatch_tag = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800471 struct dt_entry *best_match_dt_entry = NULL;
Shashank Mittalc0f10282013-07-15 14:53:31 -0700472 uint32_t bestmatch_tag_size;
Lijuan Gao9f152862014-08-18 13:45:24 +0800473 struct dt_entry_node *dt_entry_queue = NULL;
474 struct dt_entry_node *dt_node_tmp1 = NULL;
475 struct dt_entry_node *dt_node_tmp2 = NULL;
476
Lijuan Gao9f152862014-08-18 13:45:24 +0800477 /* Initialize the dtb entry node*/
478 dt_entry_queue = (struct dt_entry_node *)
479 malloc(sizeof(struct dt_entry_node));
480
481 if (!dt_entry_queue) {
482 dprintf(CRITICAL, "Out of memory\n");
483 return NULL;
484 }
485 list_initialize(&dt_entry_queue->node);
486
Matthew Qinbb7923d2015-02-09 10:56:09 +0800487 if (dtb_offset)
488 app_dtb_offset = dtb_offset;
489 else
490 memcpy((void*) &app_dtb_offset, (void*) (kernel + DTB_OFFSET), sizeof(uint32_t));
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800491
vijay kumare2a5ea82014-06-25 12:24:14 +0530492 if (((uintptr_t)kernel + (uintptr_t)app_dtb_offset) < (uintptr_t)kernel) {
493 return NULL;
494 }
Parth Dixit97e47bb2016-03-07 17:20:44 +0530495 dtb = (void *)((uintptr_t)kernel + app_dtb_offset);
496
vijay kumare2a5ea82014-06-25 12:24:14 +0530497 while (((uintptr_t)dtb + sizeof(struct fdt_header)) < (uintptr_t)kernel_end) {
Dima Zavinc46f8382013-05-03 12:23:06 -0700498 struct fdt_header dtb_hdr;
499 uint32_t dtb_size;
Dima Zavin77e41f32013-03-06 16:10:43 -0800500
Dima Zavinc46f8382013-05-03 12:23:06 -0700501 /* the DTB could be unaligned, so extract the header,
502 * and operate on it separately */
503 memcpy(&dtb_hdr, dtb, sizeof(struct fdt_header));
504 if (fdt_check_header((const void *)&dtb_hdr) != 0 ||
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +0530505 fdt_check_header_ext((const void *)&dtb_hdr) != 0 ||
vijay kumare2a5ea82014-06-25 12:24:14 +0530506 ((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) < (uintptr_t)dtb) ||
507 ((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) > (uintptr_t)kernel_end))
Dima Zavinc46f8382013-05-03 12:23:06 -0700508 break;
509 dtb_size = fdt_totalsize(&dtb_hdr);
510
Lijuan Gao9f152862014-08-18 13:45:24 +0800511 dev_tree_compatible(dtb, dtb_size, dt_entry_queue);
Dima Zavinc46f8382013-05-03 12:23:06 -0700512
513 /* goto the next device tree if any */
514 dtb += dtb_size;
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800515 }
Dima Zavinc46f8382013-05-03 12:23:06 -0700516
Lijuan Gao9f152862014-08-18 13:45:24 +0800517 best_match_dt_entry = platform_dt_match_best(dt_entry_queue);
518 if (best_match_dt_entry){
519 bestmatch_tag = (void *)best_match_dt_entry->offset;
520 bestmatch_tag_size = best_match_dt_entry->size;
521 dprintf(INFO, "Best match DTB tags %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
522 best_match_dt_entry->platform_id, best_match_dt_entry->variant_id,
523 best_match_dt_entry->board_hw_subtype, best_match_dt_entry->soc_rev,
524 best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],
525 best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],
526 best_match_dt_entry->offset, best_match_dt_entry->size);
527 dprintf(INFO, "Using pmic info 0x%0x/0x%x/0x%x/0x%0x for device 0x%0x/0x%x/0x%x/0x%0x\n",
528 best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],
529 best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],
530 board_pmic_target(0), board_pmic_target(1),
531 board_pmic_target(2), board_pmic_target(3));
532 }
533 /* free queue's memory */
534 list_for_every_entry(&dt_entry_queue->node, dt_node_tmp1, dt_node, node) {
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -0800535 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +0800536 dt_entry_list_delete(dt_node_tmp1);
537 dt_node_tmp1 = dt_node_tmp2;
538 }
539
Shashank Mittalc0f10282013-07-15 14:53:31 -0700540 if(bestmatch_tag) {
Parth Dixitc2f0cb92016-03-10 10:40:14 +0530541 if (check_aboot_addr_range_overlap((uintptr_t)tags, bestmatch_tag_size)) {
542 dprintf(CRITICAL, "Tags addresses overlap with aboot addresses.\n");
543 return NULL;
544 }
Shashank Mittalc0f10282013-07-15 14:53:31 -0700545 memcpy(tags, bestmatch_tag, bestmatch_tag_size);
546 /* clear out the old DTB magic so kernel doesn't find it */
547 *((uint32_t *)(kernel + app_dtb_offset)) = 0;
548 return tags;
549 }
550
Dima Zavinc46f8382013-05-03 12:23:06 -0700551 dprintf(CRITICAL, "DTB offset is incorrect, kernel image does not have appended DTB\n");
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800552
David Ng59c4a782015-05-14 15:51:44 -0700553 dprintf(INFO, "Device info 0x%08x/%08x/0x%08x/%u, pmic 0x%0x/0x%x/0x%x/0x%0x\n",
554 board_platform_id(), board_soc_version(),
555 board_target_id(), board_hardware_subtype(),
556 board_pmic_target(0), board_pmic_target(1),
557 board_pmic_target(2), board_pmic_target(3));
Dima Zavin77e41f32013-03-06 16:10:43 -0800558 return NULL;
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800559}
560
Joel Kingaa335dc2013-06-03 16:11:08 -0700561/* Returns 0 if the device tree is valid. */
Deepa Dinamani87252952013-09-09 13:58:27 -0700562int dev_tree_validate(struct dt_table *table, unsigned int page_size, uint32_t *dt_hdr_size)
Joel Kingaa335dc2013-06-03 16:11:08 -0700563{
564 int dt_entry_size;
Channagoud Kadabid87c2772014-06-20 15:41:55 -0700565 uint64_t hdr_size;
Joel Kingaa335dc2013-06-03 16:11:08 -0700566
567 /* Validate the device tree table header */
568 if(table->magic != DEV_TREE_MAGIC) {
569 dprintf(CRITICAL, "ERROR: Bad magic in device tree table \n");
570 return -1;
571 }
572
573 if (table->version == DEV_TREE_VERSION_V1) {
574 dt_entry_size = sizeof(struct dt_entry_v1);
575 } else if (table->version == DEV_TREE_VERSION_V2) {
Lijuan Gao9f152862014-08-18 13:45:24 +0800576 dt_entry_size = sizeof(struct dt_entry_v2);
577 } else if (table->version == DEV_TREE_VERSION_V3) {
Joel Kingaa335dc2013-06-03 16:11:08 -0700578 dt_entry_size = sizeof(struct dt_entry);
579 } else {
580 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
581 table->version);
582 return -1;
583 }
584
Channagoud Kadabid87c2772014-06-20 15:41:55 -0700585 hdr_size = (uint64_t)table->num_entries * dt_entry_size + DEV_TREE_HEADER_SIZE;
586
Deepa Dinamani87252952013-09-09 13:58:27 -0700587 /* Roundup to page_size. */
588 hdr_size = ROUNDUP(hdr_size, page_size);
589
Channagoud Kadabid87c2772014-06-20 15:41:55 -0700590 if (hdr_size > UINT_MAX)
591 return -1;
592 else
593 *dt_hdr_size = hdr_size & UINT_MAX;
Joel Kingaa335dc2013-06-03 16:11:08 -0700594
595 return 0;
596}
597
Lijuan Gao9f152862014-08-18 13:45:24 +0800598static int platform_dt_absolute_match(struct dt_entry *cur_dt_entry, struct dt_entry_node *dt_list)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700599{
Lijuan Gaof8e95722014-12-23 03:03:12 -0500600 uint32_t cur_dt_hlos_ddr;
Lijuan Gao9f152862014-08-18 13:45:24 +0800601 uint32_t cur_dt_hw_platform;
602 uint32_t cur_dt_hw_subtype;
603 uint32_t cur_dt_msm_id;
604 dt_node *dt_node_tmp = NULL;
Channagoud Kadabi571193a2014-02-05 13:58:49 -0800605
Lijuan Gao9f152862014-08-18 13:45:24 +0800606 /* Platform-id
607 * bit no |31 24|23 16|15 0|
608 * |reserved|foundry-id|msm-id|
609 */
610 cur_dt_msm_id = (cur_dt_entry->platform_id & 0x0000ffff);
611 cur_dt_hw_platform = (cur_dt_entry->variant_id & 0x000000ff);
Lijuan Gao0621b862014-09-02 10:02:52 +0800612 cur_dt_hw_subtype = (cur_dt_entry->board_hw_subtype & 0xff);
Lijuan Gao9f152862014-08-18 13:45:24 +0800613
Lijuan Gaof8e95722014-12-23 03:03:12 -0500614 /* Determine the bits 10:8 to check the DT with the DDR Size */
615 cur_dt_hlos_ddr = (cur_dt_entry->board_hw_subtype & 0x700);
Channagoud Kadabi571193a2014-02-05 13:58:49 -0800616
Lijuan Gao9f152862014-08-18 13:45:24 +0800617 /* 1. must match the msm_id, platform_hw_id, platform_subtype and DDR size
618 * soc, board major/minor, pmic major/minor must less than board info
619 * 2. find the matched DTB then return 1
620 * 3. otherwise return 0
Maria Yu2e2d2c22013-07-03 19:20:33 +0800621 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800622 if((cur_dt_msm_id == (board_platform_id() & 0x0000ffff)) &&
623 (cur_dt_hw_platform == board_hardware_id()) &&
624 (cur_dt_hw_subtype == board_hardware_subtype()) &&
Lijuan Gaof8e95722014-12-23 03:03:12 -0500625 (cur_dt_hlos_ddr == (target_get_hlos_subtype() & 0x700)) &&
Lijuan Gao9f152862014-08-18 13:45:24 +0800626 (cur_dt_entry->soc_rev <= board_soc_version()) &&
627 ((cur_dt_entry->variant_id & 0x00ffff00) <= (board_target_id() & 0x00ffff00)) &&
628 ((cur_dt_entry->pmic_rev[0] & 0x00ffff00) <= (board_pmic_target(0) & 0x00ffff00)) &&
629 ((cur_dt_entry->pmic_rev[1] & 0x00ffff00) <= (board_pmic_target(1) & 0x00ffff00)) &&
630 ((cur_dt_entry->pmic_rev[2] & 0x00ffff00) <= (board_pmic_target(2) & 0x00ffff00)) &&
631 ((cur_dt_entry->pmic_rev[3] & 0x00ffff00) <= (board_pmic_target(3) & 0x00ffff00))) {
Maria Yu2e2d2c22013-07-03 19:20:33 +0800632
Lijuan Gao9f152862014-08-18 13:45:24 +0800633 dt_node_tmp = dt_entry_list_init();
634 memcpy((char*)dt_node_tmp->dt_entry_m,(char*)cur_dt_entry, sizeof(struct dt_entry));
635
636 dprintf(SPEW, "Add DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
637 dt_node_tmp->dt_entry_m->platform_id, dt_node_tmp->dt_entry_m->variant_id,
638 dt_node_tmp->dt_entry_m->board_hw_subtype, dt_node_tmp->dt_entry_m->soc_rev,
639 dt_node_tmp->dt_entry_m->pmic_rev[0], dt_node_tmp->dt_entry_m->pmic_rev[1],
640 dt_node_tmp->dt_entry_m->pmic_rev[2], dt_node_tmp->dt_entry_m->pmic_rev[3],
641 dt_node_tmp->dt_entry_m->offset, dt_node_tmp->dt_entry_m->size);
642
643 insert_dt_entry_in_queue(dt_list, dt_node_tmp);
644 return 1;
645 }
646 return 0;
647}
648
649static int platform_dt_absolute_compat_match(struct dt_entry_node *dt_list, uint32_t dtb_info) {
650 struct dt_entry_node *dt_node_tmp1 = NULL;
651 struct dt_entry_node *dt_node_tmp2 = NULL;
652 uint32_t current_info = 0;
653 uint32_t board_info = 0;
654 uint32_t best_info = 0;
655 uint32_t current_pmic_model[4] = {0, 0, 0, 0};
656 uint32_t board_pmic_model[4] = {0, 0, 0, 0};
657 uint32_t best_pmic_model[4] = {0, 0, 0, 0};
658 uint32_t delete_current_dt = 0;
659 uint32_t i;
660
661 /* start to select the exact entry
662 * default to exact match 0, if find current DTB entry info is the same as board info,
663 * then exact match board info.
664 */
665 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
666 if (!dt_node_tmp1){
667 dprintf(SPEW, "Current node is the end\n");
668 break;
669 }
670 switch(dtb_info) {
671 case DTB_FOUNDRY:
672 current_info = ((dt_node_tmp1->dt_entry_m->platform_id) & 0x00ff0000);
Channagoud Kadabi4cffc272014-10-29 11:23:26 -0700673 board_info = board_foundry_id() << 16;
Lijuan Gao9f152862014-08-18 13:45:24 +0800674 break;
675 case DTB_PMIC_MODEL:
676 for (i = 0; i < 4; i++) {
677 current_pmic_model[i] = (dt_node_tmp1->dt_entry_m->pmic_rev[i] & 0xff);
678 board_pmic_model[i] = (board_pmic_target(i) & 0xff);
679 }
680 break;
Lijuan Gaof8e95722014-12-23 03:03:12 -0500681 case DTB_PANEL_TYPE:
682 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0x1800);
683 board_info = (target_get_hlos_subtype() & 0x1800);
684 break;
685 case DTB_BOOT_DEVICE:
686 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0xf0000);
687 board_info = (target_get_hlos_subtype() & 0xf0000);
688 break;
Lijuan Gao9f152862014-08-18 13:45:24 +0800689 default:
690 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
691 dtb_info);
Maria Yuca51ee22013-06-27 21:45:24 +0800692 return 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800693 }
694
695 if (dtb_info == DTB_PMIC_MODEL) {
696 if ((current_pmic_model[0] == board_pmic_model[0]) &&
697 (current_pmic_model[1] == board_pmic_model[1]) &&
698 (current_pmic_model[2] == board_pmic_model[2]) &&
699 (current_pmic_model[3] == board_pmic_model[3])) {
700
701 for (i = 0; i < 4; i++) {
702 best_pmic_model[i] = current_pmic_model[i];
703 }
704 break;
705 }
706 } else {
707 if (current_info == board_info) {
708 best_info = current_info;
709 break;
710 }
711 }
712 }
713
714 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
715 if (!dt_node_tmp1){
716 dprintf(SPEW, "Current node is the end\n");
717 break;
718 }
719 switch(dtb_info) {
720 case DTB_FOUNDRY:
721 current_info = ((dt_node_tmp1->dt_entry_m->platform_id) & 0x00ff0000);
722 break;
723 case DTB_PMIC_MODEL:
724 for (i = 0; i < 4; i++) {
725 current_pmic_model[i] = (dt_node_tmp1->dt_entry_m->pmic_rev[i] & 0xff);
726 }
727 break;
Lijuan Gaof8e95722014-12-23 03:03:12 -0500728 case DTB_PANEL_TYPE:
729 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0x1800);
730 break;
731 case DTB_BOOT_DEVICE:
732 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0xf0000);
733 break;
Lijuan Gao9f152862014-08-18 13:45:24 +0800734 default:
735 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
736 dtb_info);
737 return 0;
738 }
739
740 if (dtb_info == DTB_PMIC_MODEL) {
741 if ((current_pmic_model[0] != best_pmic_model[0]) ||
742 (current_pmic_model[1] != best_pmic_model[1]) ||
743 (current_pmic_model[2] != best_pmic_model[2]) ||
744 (current_pmic_model[3] != best_pmic_model[3])) {
745
746 delete_current_dt = 1;
747 }
748 } else {
749 if (current_info != best_info) {
750 delete_current_dt = 1;
751 }
752 }
753
754 if (delete_current_dt) {
755 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
756 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
757 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
758 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
759 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
760 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
761
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -0800762 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +0800763 dt_entry_list_delete(dt_node_tmp1);
764 dt_node_tmp1 = dt_node_tmp2;
765 delete_current_dt = 0;
Maria Yuca51ee22013-06-27 21:45:24 +0800766 }
767 }
Maria Yuca51ee22013-06-27 21:45:24 +0800768
Maria Yu2e2d2c22013-07-03 19:20:33 +0800769 return 1;
Maria Yuca51ee22013-06-27 21:45:24 +0800770}
771
Lijuan Gao9f152862014-08-18 13:45:24 +0800772static int update_dtb_entry_node(struct dt_entry_node *dt_list, uint32_t dtb_info) {
773 struct dt_entry_node *dt_node_tmp1 = NULL;
774 struct dt_entry_node *dt_node_tmp2 = NULL;
775 uint32_t current_info = 0;
776 uint32_t board_info = 0;
777 uint32_t best_info = 0;
778
779 /* start to select the best entry*/
780 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
781 if (!dt_node_tmp1){
782 dprintf(SPEW, "Current node is the end\n");
783 break;
784 }
785 switch(dtb_info) {
786 case DTB_SOC:
787 current_info = dt_node_tmp1->dt_entry_m->soc_rev;
788 board_info = board_soc_version();
789 break;
790 case DTB_MAJOR_MINOR:
791 current_info = ((dt_node_tmp1->dt_entry_m->variant_id) & 0x00ffff00);
792 board_info = (board_target_id() & 0x00ffff00);
793 break;
794 case DTB_PMIC0:
795 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[0]) & 0x00ffff00);
796 board_info = (board_pmic_target(0) & 0x00ffff00);
797 break;
798 case DTB_PMIC1:
799 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[1]) & 0x00ffff00);
800 board_info = (board_pmic_target(1) & 0x00ffff00);
801 break;
802 case DTB_PMIC2:
803 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[2]) & 0x00ffff00);
804 board_info = (board_pmic_target(2) & 0x00ffff00);
805 break;
806 case DTB_PMIC3:
807 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[3]) & 0x00ffff00);
808 board_info = (board_pmic_target(3) & 0x00ffff00);
809 break;
810 default:
811 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
812 dtb_info);
813 return 0;
814 }
815
816 if (current_info == board_info) {
817 best_info = current_info;
818 break;
819 }
820 if ((current_info < board_info) && (current_info > best_info)) {
821 best_info = current_info;
822 }
823 if (current_info < best_info) {
824 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
825 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
826 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
827 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
828 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
829 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
830
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -0800831 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +0800832 dt_entry_list_delete(dt_node_tmp1);
833 dt_node_tmp1 = dt_node_tmp2;
834 }
835 }
836
837 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
838 if (!dt_node_tmp1){
839 dprintf(SPEW, "Current node is the end\n");
840 break;
841 }
842 switch(dtb_info) {
843 case DTB_SOC:
844 current_info = dt_node_tmp1->dt_entry_m->soc_rev;
845 break;
846 case DTB_MAJOR_MINOR:
847 current_info = ((dt_node_tmp1->dt_entry_m->variant_id) & 0x00ffff00);
848 break;
849 case DTB_PMIC0:
850 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[0]) & 0x00ffff00);
851 break;
852 case DTB_PMIC1:
853 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[1]) & 0x00ffff00);
854 break;
855 case DTB_PMIC2:
856 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[2]) & 0x00ffff00);
857 break;
858 case DTB_PMIC3:
859 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[3]) & 0x00ffff00);
860 break;
861 default:
862 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
863 dtb_info);
864 return 0;
865 }
866
867 if (current_info != best_info) {
868 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
869 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
870 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
871 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
872 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
873 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
874
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -0800875 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +0800876 dt_entry_list_delete(dt_node_tmp1);
877 dt_node_tmp1 = dt_node_tmp2;
878 }
879 }
880 return 1;
881}
882
883static struct dt_entry *platform_dt_match_best(struct dt_entry_node *dt_list)
884{
885 struct dt_entry_node *dt_node_tmp1 = NULL;
886
887 /* check Foundry id
888 * the foundry id must exact match board founddry id, this is compatibility check,
889 * if couldn't find the exact match from DTB, will exact match 0x0.
890 */
891 if (!platform_dt_absolute_compat_match(dt_list, DTB_FOUNDRY))
892 return NULL;
893
894 /* check PMIC model
895 * the PMIC model must exact match board PMIC model, this is compatibility check,
896 * if couldn't find the exact match from DTB, will exact match 0x0.
897 */
898 if (!platform_dt_absolute_compat_match(dt_list, DTB_PMIC_MODEL))
899 return NULL;
900
Lijuan Gaof8e95722014-12-23 03:03:12 -0500901 /* check panel type
902 * the panel type must exact match board panel type, this is compatibility check,
903 * if couldn't find the exact match from DTB, will exact match 0x0.
904 */
905 if (!platform_dt_absolute_compat_match(dt_list, DTB_PANEL_TYPE))
906 return NULL;
907
908 /* check boot device subtype
909 * the boot device subtype must exact match board boot device subtype, this is compatibility check,
910 * if couldn't find the exact match from DTB, will exact match 0x0.
911 */
912 if (!platform_dt_absolute_compat_match(dt_list, DTB_BOOT_DEVICE))
913 return NULL;
914
Lijuan Gao9f152862014-08-18 13:45:24 +0800915 /* check soc version
916 * the suitable soc version must less than or equal to board soc version
917 */
918 if (!update_dtb_entry_node(dt_list, DTB_SOC))
919 return NULL;
920
921 /*check major and minor version
922 * the suitable major&minor version must less than or equal to board major&minor version
923 */
924 if (!update_dtb_entry_node(dt_list, DTB_MAJOR_MINOR))
925 return NULL;
926
927 /*check pmic info
928 * the suitable pmic major&minor info must less than or equal to board pmic major&minor version
929 */
930 if (!update_dtb_entry_node(dt_list, DTB_PMIC0))
931 return NULL;
932 if (!update_dtb_entry_node(dt_list, DTB_PMIC1))
933 return NULL;
934 if (!update_dtb_entry_node(dt_list, DTB_PMIC2))
935 return NULL;
936 if (!update_dtb_entry_node(dt_list, DTB_PMIC3))
937 return NULL;
938
939 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
940 if (!dt_node_tmp1) {
941 dprintf(CRITICAL, "ERROR: Couldn't find the suitable DTB!\n");
942 return NULL;
943 }
944 if (dt_node_tmp1->dt_entry_m)
945 return dt_node_tmp1->dt_entry_m;
946 }
947
948 return NULL;
949}
950
951/* Function to obtain the index information for the correct device tree
952 * based on the platform data.
953 * If a matching device tree is found, the information is returned in the
954 * "dt_entry_info" out parameter and a function value of 0 is returned, otherwise
955 * a non-zero function value is returned.
956 */
957int dev_tree_get_entry_info(struct dt_table *table, struct dt_entry *dt_entry_info)
Maria Yuca51ee22013-06-27 21:45:24 +0800958{
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700959 uint32_t i;
Lijuan Gao9f152862014-08-18 13:45:24 +0800960 unsigned char *table_ptr = NULL;
Joel Kingaa335dc2013-06-03 16:11:08 -0700961 struct dt_entry dt_entry_buf_1;
Lijuan Gao9f152862014-08-18 13:45:24 +0800962 struct dt_entry *cur_dt_entry = NULL;
963 struct dt_entry *best_match_dt_entry = NULL;
964 struct dt_entry_v1 *dt_entry_v1 = NULL;
965 struct dt_entry_v2 *dt_entry_v2 = NULL;
966 struct dt_entry_node *dt_entry_queue = NULL;
967 struct dt_entry_node *dt_node_tmp1 = NULL;
968 struct dt_entry_node *dt_node_tmp2 = NULL;
Maria Yu2e2d2c22013-07-03 19:20:33 +0800969 uint32_t found = 0;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700970
Joel Kingaa335dc2013-06-03 16:11:08 -0700971 if (!dt_entry_info) {
972 dprintf(CRITICAL, "ERROR: Bad parameter passed to %s \n",
973 __func__);
974 return -1;
975 }
976
977 table_ptr = (unsigned char *)table + DEV_TREE_HEADER_SIZE;
978 cur_dt_entry = &dt_entry_buf_1;
979 best_match_dt_entry = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800980 dt_entry_queue = (struct dt_entry_node *)
981 malloc(sizeof(struct dt_entry_node));
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700982
Lijuan Gao9f152862014-08-18 13:45:24 +0800983 if (!dt_entry_queue) {
984 dprintf(CRITICAL, "Out of memory\n");
985 return -1;
986 }
987
988 list_initialize(&dt_entry_queue->node);
989 dprintf(INFO, "DTB Total entry: %d, DTB version: %d\n", table->num_entries, table->version);
Maria Yu2e2d2c22013-07-03 19:20:33 +0800990 for(i = 0; found == 0 && i < table->num_entries; i++)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700991 {
Joel Kingaa335dc2013-06-03 16:11:08 -0700992 memset(cur_dt_entry, 0, sizeof(struct dt_entry));
993 switch(table->version) {
994 case DEV_TREE_VERSION_V1:
995 dt_entry_v1 = (struct dt_entry_v1 *)table_ptr;
996 cur_dt_entry->platform_id = dt_entry_v1->platform_id;
997 cur_dt_entry->variant_id = dt_entry_v1->variant_id;
998 cur_dt_entry->soc_rev = dt_entry_v1->soc_rev;
Lijuan Gao9f152862014-08-18 13:45:24 +0800999 cur_dt_entry->board_hw_subtype = (dt_entry_v1->variant_id >> 0x18);
1000 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
1001 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
1002 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
1003 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
Joel Kingaa335dc2013-06-03 16:11:08 -07001004 cur_dt_entry->offset = dt_entry_v1->offset;
1005 cur_dt_entry->size = dt_entry_v1->size;
1006 table_ptr += sizeof(struct dt_entry_v1);
1007 break;
1008 case DEV_TREE_VERSION_V2:
Lijuan Gao9f152862014-08-18 13:45:24 +08001009 dt_entry_v2 = (struct dt_entry_v2*)table_ptr;
1010 cur_dt_entry->platform_id = dt_entry_v2->platform_id;
1011 cur_dt_entry->variant_id = dt_entry_v2->variant_id;
1012 cur_dt_entry->soc_rev = dt_entry_v2->soc_rev;
1013 /* For V2 version of DTBs we have platform version field as part
1014 * of variant ID, in such case the subtype will be mentioned as 0x0
1015 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
1016 * SS -- Subtype
1017 * PM -- Platform major version
1018 * Pm -- Platform minor version
1019 * PH -- Platform hardware CDP/MTP
1020 * In such case to make it compatible with LK algorithm move the subtype
1021 * from variant_id to subtype field
1022 */
1023 if (dt_entry_v2->board_hw_subtype == 0)
1024 cur_dt_entry->board_hw_subtype = (cur_dt_entry->variant_id >> 0x18);
1025 else
1026 cur_dt_entry->board_hw_subtype = dt_entry_v2->board_hw_subtype;
1027 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
1028 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
1029 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
1030 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
1031 cur_dt_entry->offset = dt_entry_v2->offset;
1032 cur_dt_entry->size = dt_entry_v2->size;
1033 table_ptr += sizeof(struct dt_entry_v2);
1034 break;
1035 case DEV_TREE_VERSION_V3:
Joel Kingaa335dc2013-06-03 16:11:08 -07001036 memcpy(cur_dt_entry, (struct dt_entry *)table_ptr,
1037 sizeof(struct dt_entry));
Lijuan Gao9f152862014-08-18 13:45:24 +08001038 /* For V3 version of DTBs we have platform version field as part
1039 * of variant ID, in such case the subtype will be mentioned as 0x0
1040 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
1041 * SS -- Subtype
1042 * PM -- Platform major version
1043 * Pm -- Platform minor version
1044 * PH -- Platform hardware CDP/MTP
1045 * In such case to make it compatible with LK algorithm move the subtype
1046 * from variant_id to subtype field
1047 */
1048 if (cur_dt_entry->board_hw_subtype == 0)
1049 cur_dt_entry->board_hw_subtype = (cur_dt_entry->variant_id >> 0x18);
1050
Joel Kingaa335dc2013-06-03 16:11:08 -07001051 table_ptr += sizeof(struct dt_entry);
1052 break;
1053 default:
1054 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
1055 table->version);
Lijuan Gao9f152862014-08-18 13:45:24 +08001056 free(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001057 return -1;
1058 }
1059
Lijuan Gao9f152862014-08-18 13:45:24 +08001060 /* DTBs must match the platform_id, platform_hw_id, platform_subtype and DDR size.
1061 * The satisfactory DTBs are stored in dt_entry_queue
1062 */
1063 platform_dt_absolute_match(cur_dt_entry, dt_entry_queue);
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -08001064
Lijuan Gao9f152862014-08-18 13:45:24 +08001065 }
1066 best_match_dt_entry = platform_dt_match_best(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001067 if (best_match_dt_entry) {
1068 *dt_entry_info = *best_match_dt_entry;
Maria Yu2e2d2c22013-07-03 19:20:33 +08001069 found = 1;
1070 }
1071
1072 if (found != 0) {
Sundarajan Srinivasan763c0db2014-05-20 17:08:36 -07001073 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 -07001074 dt_entry_info->platform_id, dt_entry_info->soc_rev,
1075 dt_entry_info->variant_id, dt_entry_info->board_hw_subtype,
Lijuan Gao9f152862014-08-18 13:45:24 +08001076 board_platform_id(), board_soc_version(),
1077 board_target_id(), board_hardware_subtype());
1078 if (dt_entry_info->pmic_rev[0] == 0 && dt_entry_info->pmic_rev[0] == 0 &&
1079 dt_entry_info->pmic_rev[0] == 0 && dt_entry_info->pmic_rev[0] == 0) {
1080 dprintf(SPEW, "No maintain pmic info in DTB, device pmic info is 0x%0x/0x%x/0x%x/0x%0x\n",
1081 board_pmic_target(0), board_pmic_target(1),
1082 board_pmic_target(2), board_pmic_target(3));
1083 } else {
1084 dprintf(INFO, "Using pmic info 0x%0x/0x%x/0x%x/0x%0x for device 0x%0x/0x%x/0x%x/0x%0x\n",
1085 dt_entry_info->pmic_rev[0], dt_entry_info->pmic_rev[1],
1086 dt_entry_info->pmic_rev[2], dt_entry_info->pmic_rev[3],
1087 board_pmic_target(0), board_pmic_target(1),
1088 board_pmic_target(2), board_pmic_target(3));
1089 }
Joel Kingaa335dc2013-06-03 16:11:08 -07001090 return 0;
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -08001091 }
1092
Lijuan Gao9f152862014-08-18 13:45:24 +08001093 dprintf(CRITICAL, "ERROR: Unable to find suitable device tree for device (%u/0x%08x/0x%08x/%u)\n",
1094 board_platform_id(), board_soc_version(),
1095 board_target_id(), board_hardware_subtype());
1096
1097 list_for_every_entry(&dt_entry_queue->node, dt_node_tmp1, dt_node, node) {
1098 /* free node memory */
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001099 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001100 dt_entry_list_delete(dt_node_tmp1);
1101 dt_node_tmp1 = dt_node_tmp2;
1102 }
1103 free(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001104 return -1;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001105}
1106
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001107/* Function to add the first RAM partition info to the device tree.
1108 * Note: The function replaces the reg property in the "/memory" node
1109 * with the addr and size provided.
1110 */
1111int dev_tree_add_first_mem_info(uint32_t *fdt, uint32_t offset, uint32_t addr, uint32_t size)
1112{
1113 int ret;
1114
1115 ret = fdt_setprop_u32(fdt, offset, "reg", addr);
1116
1117 if (ret)
1118 {
1119 dprintf(CRITICAL, "Failed to add the memory information addr: %d\n",
1120 ret);
1121 }
1122
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001123 ret = fdt_appendprop_u32(fdt, offset, "reg", size);
1124
1125 if (ret)
1126 {
1127 dprintf(CRITICAL, "Failed to add the memory information size: %d\n",
1128 ret);
1129 }
1130
1131 return ret;
1132}
1133
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001134static 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 -07001135{
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001136 int len;
1137 uint32_t *valp;
1138 int ret;
1139 uint32_t offset;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001140
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001141 mem_node->offset = mem_node_offset;
1142
1143 /* Get offset of the root node */
1144 ret = fdt_path_offset(fdt, "/");
1145 if (ret < 0)
1146 {
1147 dprintf(CRITICAL, "Could not find memory node.\n");
1148 return ret;
1149 }
1150
1151 offset = ret;
1152
1153 /* Find the #address-cells size. */
1154 valp = (uint32_t*)fdt_getprop(fdt, offset, "#address-cells", &len);
Lijuan Gaoae0927b2014-07-18 17:16:16 +08001155 if (len <= 0 || !valp)
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001156 {
1157 if (len == -FDT_ERR_NOTFOUND)
1158 {
1159 /* Property not found.
1160 * Assume standard sizes.
1161 */
1162 mem_node->addr_cell_size = 2;
1163 dprintf(CRITICAL, "Using default #addr_cell_size: %u\n", mem_node->addr_cell_size);
1164 }
1165 else
1166 {
1167 dprintf(CRITICAL, "Error finding the #address-cells property\n");
1168 return len;
1169 }
1170 }
1171 else
1172 mem_node->addr_cell_size = fdt32_to_cpu(*valp);
1173
1174 /* Find the #size-cells size. */
1175 valp = (uint32_t*)fdt_getprop(fdt, offset, "#size-cells", &len);
Lijuan Gaoae0927b2014-07-18 17:16:16 +08001176 if (len <= 0 || !valp)
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001177 {
1178 if (len == -FDT_ERR_NOTFOUND)
1179 {
1180 /* Property not found.
1181 * Assume standard sizes.
1182 */
1183 mem_node->size_cell_size = 1;
1184 dprintf(CRITICAL, "Using default #size_cell_size: %u\n", mem_node->size_cell_size);
1185 }
1186 else
1187 {
1188 dprintf(CRITICAL, "Error finding the #size-cells property\n");
1189 return len;
1190 }
1191 }
1192 else
1193 mem_node->size_cell_size = fdt32_to_cpu(*valp);
1194
1195 return 0;
1196}
1197
1198static void dev_tree_update_memory_node(uint32_t offset)
1199{
1200 mem_node.offset = offset;
1201 mem_node.addr_cell_size = 1;
1202 mem_node.size_cell_size = 1;
1203}
1204
1205/* Function to add the subsequent RAM partition info to the device tree. */
1206int dev_tree_add_mem_info(void *fdt, uint32_t offset, uint64_t addr, uint64_t size)
1207{
1208 int ret = 0;
1209
1210 if(smem_get_ram_ptable_version() >= 1)
1211 {
1212 ret = dev_tree_query_memory_cell_sizes(fdt, &mem_node, offset);
1213 if (ret < 0)
1214 {
1215 dprintf(CRITICAL, "Could not find #address-cells and #size-cells properties: ret %d\n", ret);
1216 return ret;
1217 }
1218
1219 }
1220 else
1221 {
1222 dev_tree_update_memory_node(offset);
1223 }
1224
1225 if (!(mem_node.mem_info_cnt))
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001226 {
1227 /* Replace any other reg prop in the memory node. */
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001228
1229 /* cell_size is the number of 32 bit words used to represent an address/length in the device tree.
1230 * memory node in DT can be either 32-bit(cell-size = 1) or 64-bit(cell-size = 2).So when updating
1231 * the memory node in the device tree, we write one word or two words based on cell_size = 1 or 2.
1232 */
1233
1234 if(mem_node.addr_cell_size == 2)
1235 {
1236 ret = fdt_setprop_u32(fdt, mem_node.offset, "reg", addr >> 32);
1237 if(ret)
1238 {
1239 dprintf(CRITICAL, "ERROR: Could not set prop reg for memory node\n");
1240 return ret;
1241 }
1242
1243 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1244 if(ret)
1245 {
1246 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1247 return ret;
1248 }
1249 }
1250 else
1251 {
1252 ret = fdt_setprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1253 if(ret)
1254 {
1255 dprintf(CRITICAL, "ERROR: Could not set prop reg for memory node\n");
1256 return ret;
1257 }
1258 }
1259
1260 mem_node.mem_info_cnt = 1;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001261 }
1262 else
1263 {
1264 /* Append the mem info to the reg prop for subsequent nodes. */
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001265 if(mem_node.addr_cell_size == 2)
1266 {
1267 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", addr >> 32);
1268 if(ret)
1269 {
1270 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1271 return ret;
1272 }
1273 }
1274
1275 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1276 if(ret)
1277 {
1278 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1279 return ret;
1280 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001281 }
1282
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001283 if(mem_node.size_cell_size == 2)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001284 {
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001285 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", size>>32);
1286 if(ret)
1287 {
1288 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1289 return ret;
1290 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001291 }
1292
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001293 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)size);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001294
1295 if (ret)
1296 {
1297 dprintf(CRITICAL, "Failed to add the memory information size: %d\n",
1298 ret);
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001299 return ret;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001300 }
1301
1302 return ret;
1303}
1304
1305/* Top level function that updates the device tree. */
1306int update_device_tree(void *fdt, const char *cmdline,
1307 void *ramdisk, uint32_t ramdisk_size)
1308{
1309 int ret = 0;
1310 uint32_t offset;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001311
1312 /* Check the device tree header */
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +05301313 ret = fdt_check_header(fdt) || fdt_check_header_ext(fdt);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001314 if (ret)
1315 {
1316 dprintf(CRITICAL, "Invalid device tree header \n");
1317 return ret;
1318 }
1319
P.V. Phani Kumar9cd95102016-03-09 12:35:23 +05301320 if (check_aboot_addr_range_overlap((uint32_t)fdt,
1321 (fdt_totalsize(fdt) + DTB_PAD_SIZE))) {
1322 dprintf(CRITICAL, "Error: Fdt addresses overlap with aboot addresses.\n");
1323 return ret;
1324 }
1325
Deepa Dinamani1c970732013-04-19 14:23:01 -07001326 /* Add padding to make space for new nodes and properties. */
1327 ret = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + DTB_PAD_SIZE);
1328 if (ret!= 0)
1329 {
1330 dprintf(CRITICAL, "Failed to move/resize dtb buffer: %d\n", ret);
1331 return ret;
1332 }
1333
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001334 /* Get offset of the memory node */
1335 ret = fdt_path_offset(fdt, "/memory");
1336 if (ret < 0)
1337 {
1338 dprintf(CRITICAL, "Could not find memory node.\n");
1339 return ret;
1340 }
1341
1342 offset = ret;
1343
1344 ret = target_dev_tree_mem(fdt, offset);
1345 if(ret)
1346 {
1347 dprintf(CRITICAL, "ERROR: Cannot update memory node\n");
1348 return ret;
1349 }
1350
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001351 /* Get offset of the chosen node */
1352 ret = fdt_path_offset(fdt, "/chosen");
1353 if (ret < 0)
1354 {
1355 dprintf(CRITICAL, "Could not find chosen node.\n");
1356 return ret;
1357 }
1358
1359 offset = ret;
Maria Yuabde9542014-07-07 14:49:34 +08001360 if (cmdline)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001361 {
Maria Yuabde9542014-07-07 14:49:34 +08001362 /* Adding the cmdline to the chosen node */
1363 ret = fdt_appendprop_string(fdt, offset, (const char*)"bootargs", (const void*)cmdline);
1364 if (ret)
1365 {
1366 dprintf(CRITICAL, "ERROR: Cannot update chosen node [bootargs]\n");
1367 return ret;
1368 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001369 }
1370
Joonwoo Parka5b5f492014-02-13 18:24:48 -08001371 if (ramdisk_size) {
1372 /* Adding the initrd-start to the chosen node */
1373 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-start",
1374 (uint32_t)ramdisk);
1375 if (ret)
1376 {
1377 dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-start]\n");
1378 return ret;
1379 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001380
Joonwoo Parka5b5f492014-02-13 18:24:48 -08001381 /* Adding the initrd-end to the chosen node */
1382 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-end",
1383 ((uint32_t)ramdisk + ramdisk_size));
1384 if (ret)
1385 {
1386 dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-end]\n");
1387 return ret;
1388 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001389 }
1390
Kishor PK536904a2017-07-13 17:18:59 +05301391#if ENABLE_BOOTDEVICE_MOUNT
1392 /* Update fstab node */
1393 dprintf(SPEW, "Start of fstab node update:%zu ms\n", platform_get_sclk_count());
1394 if (update_fstab_node(fdt) != 0) {
1395 dprintf(CRITICAL, "ERROR: Cannot update fstab node\n");
1396 return ret;
1397 }
1398 dprintf(SPEW, "End of fstab node update:%zu ms\n", platform_get_sclk_count());
1399#endif
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001400 fdt_pack(fdt);
1401
Channagoud Kadabiffaea422014-12-05 15:45:41 -08001402#if ENABLE_PARTIAL_GOODS_SUPPORT
1403 update_partial_goods_dtb_nodes(fdt);
1404#endif
1405
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001406 return ret;
1407}
Kishor PK536904a2017-07-13 17:18:59 +05301408
1409#if ENABLE_BOOTDEVICE_MOUNT
1410/*Update device tree for fstab node */
1411static int update_fstab_node(void *fdt)
1412{
1413 int ret = 0;
1414 int str_len = 0;
1415 int parent_offset = 0;
1416 int subnode_offset = 0;
1417 int prop_length = 0;
1418 int prefix_string_len = 0;
1419 char *node_name = NULL;
1420 char *boot_dev_buf = NULL;
1421 char *new_str = NULL;
1422 char *prefix_str = NULL;
1423 char *suffix_str = NULL;
1424 const struct fdt_property *prop = NULL;
1425
1426 /* Find the parent node */
1427 parent_offset = fdt_path_offset(fdt, fstab_table.parent_node);
1428 if (parent_offset < 0) {
1429 dprintf(CRITICAL, "Failed to get parent node: fstab error: %d\n", parent_offset);
1430 return -1;
1431 }
1432 dprintf(SPEW, "Node: %s found.\n", fdt_get_name(fdt, parent_offset, NULL));
1433
1434 /* Get boot device type */
1435 boot_dev_buf = (char *) malloc(sizeof(char) * BOOT_DEV_MAX_LEN);
1436 if (!boot_dev_buf) {
1437 dprintf(CRITICAL, "Failed to allocate memory for boot device\n");
1438 return -1;
1439 }
1440
1441 new_str = (char *) malloc(sizeof(char) * NODE_PROPERTY_MAX_LEN);
1442 if (!new_str) {
1443 dprintf(CRITICAL, "Failed to allocate memory for node property string\n");
1444 return -1;
1445 }
1446
1447
1448 platform_boot_dev_cmdline(boot_dev_buf);
1449
1450 /* Get properties of all sub nodes */
1451 for (subnode_offset = fdt_first_subnode(fdt, parent_offset); subnode_offset >= 0; subnode_offset = fdt_next_subnode(fdt, subnode_offset)) {
1452 prop = fdt_get_property(fdt, subnode_offset, fstab_table.node_prop, &prop_length);
1453 node_name = (char *)(uintptr_t)fdt_get_name(fdt, subnode_offset, NULL);
1454 if (!prop) {
1455 dprintf(CRITICAL, "Property:%s is not found for sub node:%s\n", fstab_table.node_prop, node_name);
1456 } else {
1457 dprintf(CRITICAL, "Property:%s found for sub node:%s\tproperty:%s\n", fstab_table.node_prop, node_name, prop->data);
1458 /* Pointer to fdt 'dev' property string that needs to update based on the 'androidboot.bootdevice' */
1459 memset(new_str, 0, NODE_PROPERTY_MAX_LEN);
1460 prefix_str = (char *)prop->data;
1461 if (strlen(prefix_str) > NODE_PROPERTY_MAX_LEN) {
1462 dprintf(CRITICAL, "Property string length is greater than node property max length\n");
1463 continue;
1464 }
1465 suffix_str = strstr(prefix_str, fstab_table.device_path_id);
1466 if (!suffix_str) {
1467 dprintf(CRITICAL, "Property is not proper to update\n");
1468 continue;
1469 }
1470 suffix_str += strlen(fstab_table.device_path_id);
1471 prefix_string_len = strlen(prefix_str) - (strlen(suffix_str) - 1);
1472 suffix_str = strstr((suffix_str + 1), "/");
1473 str_len = strlcpy(new_str, prefix_str, prefix_string_len);
1474 if (!str_len) {
1475 dprintf(CRITICAL, "Property length is not proper to update\n");
1476 continue;
1477 }
1478 str_len = strlcat(new_str, boot_dev_buf, strlen(prefix_str));
1479 if (!str_len) {
1480 dprintf(CRITICAL, "Property length is not proper to update\n");
1481 continue;
1482 }
1483 str_len = strlcat(new_str, suffix_str, strlen(prefix_str));
1484 if (!str_len) {
1485 dprintf(CRITICAL, "Property length is not proper to update\n");
1486 continue;
1487 }
1488 /* Update the new property in the memory */
1489 memscpy(prefix_str, strlen(prefix_str), new_str, strlen(new_str) + 1);
1490 /* Update the property with new value */
1491 ret = fdt_setprop(fdt, subnode_offset, fstab_table.node_prop, (const void *)prefix_str, strlen(prefix_str) + 1);
1492 if(ret) {
1493 dprintf(CRITICAL, "Failed to update the node with new property\n");
1494 continue;
1495 }
1496 dprintf(CRITICAL, "Updated %s with new property %s\n", node_name, prop->data);
1497 }
1498 }
1499 if (boot_dev_buf)
1500 free(boot_dev_buf);
1501 if (new_str)
1502 free(new_str);
1503 return ret;
1504}
1505#endif