blob: 6a7382682eaefb0702437eb6e8089b2703ad3e8f [file] [log] [blame]
David Ng59c4a782015-05-14 15:51:44 -07001/* Copyright (c) 2012-2015, 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>
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -070042
Joel Kingaa335dc2013-06-03 16:11:08 -070043struct dt_entry_v1
44{
45 uint32_t platform_id;
46 uint32_t variant_id;
47 uint32_t soc_rev;
48 uint32_t offset;
49 uint32_t size;
50};
51
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -070052static struct dt_mem_node_info mem_node;
Lijuan Gao9f152862014-08-18 13:45:24 +080053static int platform_dt_absolute_match(struct dt_entry *cur_dt_entry, struct dt_entry_node *dt_list);
54static struct dt_entry *platform_dt_match_best(struct dt_entry_node *dt_list);
55static int update_dtb_entry_node(struct dt_entry_node *dt_list, uint32_t dtb_info);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -070056extern int target_is_emmc_boot(void);
57extern uint32_t target_dev_tree_mem(void *fdt, uint32_t memory_node_offset);
Deepa Dinamanic55f01b2013-05-30 14:05:56 -070058/* TODO: This function needs to be moved to target layer to check violations
59 * against all the other regions as well.
60 */
Vijay Kumar Pendoti9c002ad2016-03-09 13:52:45 +053061extern int check_aboot_addr_range_overlap(uintptr_t start, uint32_t size);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -070062
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +053063int fdt_check_header_ext(const void *fdt)
64{
65 uintptr_t fdt_start, fdt_end;
66 fdt_start = (uintptr_t)fdt;
67 if(fdt_start + fdt_totalsize(fdt) < fdt_start)
68 {
69 dprintf(CRITICAL,"Integer over in fdt header %s\t%d",__func__,__LINE__);
70 return FDT_ERR_BADOFFSET;
71 }
72 fdt_end = fdt_start + fdt_totalsize(fdt);
73
74 if (((uint64_t)fdt_start + (uint64_t)fdt_off_dt_struct(fdt) + (uint64_t)fdt_size_dt_struct(fdt)) > UINT_MAX)
75 return FDT_ERR_BADOFFSET;
76
77 if ((fdt_start + fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt)) > fdt_end)
78 return FDT_ERR_BADOFFSET;
79
80 if (((uint64_t)fdt_start + (uint64_t)fdt_off_dt_strings(fdt) + (uint64_t)fdt_size_dt_strings(fdt)) > UINT_MAX)
81 return FDT_ERR_BADOFFSET;
82
83 if ((fdt_start + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)) > fdt_end)
84 return FDT_ERR_BADOFFSET;
85
86 return 0;
87}
88
Shashank Mittalc0f10282013-07-15 14:53:31 -070089/* Returns soc version if platform id and hardware id matches
90 otherwise return 0xFFFFFFFF */
91#define INVALID_SOC_REV_ID 0XFFFFFFFF
Lijuan Gao9f152862014-08-18 13:45:24 +080092
93/* Add function to allocate dt entry list, used for recording
94* the entry which conform to platform_dt_absolute_match()
95*/
96static struct dt_entry_node *dt_entry_list_init(void)
97{
98 struct dt_entry_node *dt_node_member = NULL;
99
100 dt_node_member = (struct dt_entry_node *)
101 malloc(sizeof(struct dt_entry_node));
102
103 ASSERT(dt_node_member);
104
105 list_clear_node(&dt_node_member->node);
106 dt_node_member->dt_entry_m = (struct dt_entry *)
107 malloc(sizeof(struct dt_entry));
108 ASSERT(dt_node_member->dt_entry_m);
109
110 memset(dt_node_member->dt_entry_m ,0 ,sizeof(struct dt_entry));
111 return dt_node_member;
112}
113
114static void insert_dt_entry_in_queue(struct dt_entry_node *dt_list, struct dt_entry_node *dt_node_member)
115{
116 list_add_tail(&dt_list->node, &dt_node_member->node);
117}
118
119static void dt_entry_list_delete(struct dt_entry_node *dt_node_member)
120{
121 if (list_in_list(&dt_node_member->node)) {
122 list_delete(&dt_node_member->node);
123 free(dt_node_member->dt_entry_m);
124 free(dt_node_member);
125 }
126}
127
128static int dev_tree_compatible(void *dtb, uint32_t dtb_size, struct dt_entry_node *dtb_list)
Dima Zavinc46f8382013-05-03 12:23:06 -0700129{
130 int root_offset;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700131 const void *prop = NULL;
132 const char *plat_prop = NULL;
133 const char *board_prop = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800134 const char *pmic_prop = NULL;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700135 char *model = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800136 struct dt_entry *cur_dt_entry;
137 struct dt_entry *dt_entry_array = NULL;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700138 struct board_id *board_data = NULL;
139 struct plat_id *platform_data = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800140 struct pmic_id *pmic_data = NULL;
Dima Zavinc46f8382013-05-03 12:23:06 -0700141 int len;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700142 int len_board_id;
143 int len_plat_id;
144 int min_plat_id_len = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800145 int len_pmic_id;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700146 uint32_t dtb_ver;
147 uint32_t num_entries = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800148 uint32_t i, j, k, n;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700149 uint32_t msm_data_count;
150 uint32_t board_data_count;
Lijuan Gao9f152862014-08-18 13:45:24 +0800151 uint32_t pmic_data_count;
Dima Zavinc46f8382013-05-03 12:23:06 -0700152
153 root_offset = fdt_path_offset(dtb, "/");
154 if (root_offset < 0)
155 return false;
156
157 prop = fdt_getprop(dtb, root_offset, "model", &len);
158 if (prop && len > 0) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700159 model = (char *) malloc(sizeof(char) * len);
160 ASSERT(model);
161 strlcpy(model, prop, len);
Dima Zavinc46f8382013-05-03 12:23:06 -0700162 } else {
vijay kumar89d36d82014-06-30 19:32:18 +0530163 dprintf(INFO, "model does not exist in device tree\n");
Dima Zavinc46f8382013-05-03 12:23:06 -0700164 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800165 /* Find the pmic-id prop from DTB , if pmic-id is present then
166 * the DTB is version 3, otherwise find the board-id prop from DTB ,
167 * if board-id is present then the DTB is version 2 */
168 pmic_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,pmic-id", &len_pmic_id);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700169 board_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,board-id", &len_board_id);
Lijuan Gao9f152862014-08-18 13:45:24 +0800170 if (pmic_prop && (len_pmic_id > 0) && board_prop && (len_board_id > 0)) {
171 if ((len_pmic_id % PMIC_ID_SIZE) || (len_board_id % BOARD_ID_SIZE))
172 {
173 dprintf(CRITICAL, "qcom,pmic-id(%d) or qcom,board-id(%d) in device tree is not a multiple of (%d %d)\n",
174 len_pmic_id, len_board_id, PMIC_ID_SIZE, BOARD_ID_SIZE);
175 return false;
176 }
177 dtb_ver = DEV_TREE_VERSION_V3;
178 min_plat_id_len = PLAT_ID_SIZE;
179 } else if (board_prop && len_board_id > 0) {
vijay kumar89d36d82014-06-30 19:32:18 +0530180 if (len_board_id % BOARD_ID_SIZE)
181 {
182 dprintf(CRITICAL, "qcom,board-id in device tree is (%d) not a multiple of (%d)\n",
183 len_board_id, BOARD_ID_SIZE);
184 return false;
185 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700186 dtb_ver = DEV_TREE_VERSION_V2;
187 min_plat_id_len = PLAT_ID_SIZE;
Lijuan Gao9f152862014-08-18 13:45:24 +0800188 } else {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700189 dtb_ver = DEV_TREE_VERSION_V1;
190 min_plat_id_len = DT_ENTRY_V1_SIZE;
191 }
192
193 /* Get the msm-id prop from DTB */
194 plat_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,msm-id", &len_plat_id);
195 if (!plat_prop || len_plat_id <= 0) {
Dima Zavinc46f8382013-05-03 12:23:06 -0700196 dprintf(INFO, "qcom,msm-id entry not found\n");
197 return false;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700198 } else if (len_plat_id % min_plat_id_len) {
199 dprintf(INFO, "qcom,msm-id in device tree is (%d) not a multiple of (%d)\n",
200 len_plat_id, min_plat_id_len);
Dima Zavinc46f8382013-05-03 12:23:06 -0700201 return false;
202 }
Dima Zavinc46f8382013-05-03 12:23:06 -0700203
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700204 /*
205 * If DTB version is '1' look for <x y z> pair in the DTB
206 * x: platform_id
207 * y: variant_id
208 * z: SOC rev
209 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800210 if (dtb_ver == DEV_TREE_VERSION_V1) {
211 cur_dt_entry = (struct dt_entry *)
212 malloc(sizeof(struct dt_entry));
Dima Zavinc46f8382013-05-03 12:23:06 -0700213
Lijuan Gao9f152862014-08-18 13:45:24 +0800214 if (!cur_dt_entry) {
215 dprintf(CRITICAL, "Out of memory\n");
216 return false;
217 }
218 memset(cur_dt_entry, 0, sizeof(struct dt_entry));
219
220 while (len_plat_id) {
221 cur_dt_entry->platform_id = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->platform_id);
222 cur_dt_entry->variant_id = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->variant_id);
223 cur_dt_entry->soc_rev = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->soc_rev);
224 cur_dt_entry->board_hw_subtype =
225 fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->variant_id) >> 0x18;
226 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
227 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
228 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
229 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
230 cur_dt_entry->offset = (uint32_t)dtb;
231 cur_dt_entry->size = dtb_size;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700232
233 dprintf(SPEW, "Found an appended flattened device tree (%s - %u %u 0x%x)\n",
Lijuan Gao9f152862014-08-18 13:45:24 +0800234 *model ? model : "unknown",
235 cur_dt_entry->platform_id, cur_dt_entry->variant_id, cur_dt_entry->soc_rev);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700236
Lijuan Gao9f152862014-08-18 13:45:24 +0800237 if (platform_dt_absolute_match(cur_dt_entry, dtb_list)) {
238 dprintf(SPEW, "Device tree exact match the board: <%u %u 0x%x> != <%u %u 0x%x>\n",
239 cur_dt_entry->platform_id,
240 cur_dt_entry->variant_id,
241 cur_dt_entry->soc_rev,
242 board_platform_id(),
243 board_hardware_id(),
244 board_soc_version());
245
246 } else {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700247 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 +0800248 cur_dt_entry->platform_id,
249 cur_dt_entry->variant_id,
250 cur_dt_entry->soc_rev,
251 board_platform_id(),
252 board_hardware_id(),
253 board_soc_version());
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700254 plat_prop += DT_ENTRY_V1_SIZE;
255 len_plat_id -= DT_ENTRY_V1_SIZE;
256 continue;
257 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700258 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800259 free(cur_dt_entry);
260
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700261 }
262 /*
Lijuan Gao9f152862014-08-18 13:45:24 +0800263 * If DTB Version is '3' then we have split DTB with board & msm data & pmic
264 * populated saperately in board-id & msm-id & pmic-id prop respectively.
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700265 * Extract the data & prepare a look up table
266 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800267 else if (dtb_ver == DEV_TREE_VERSION_V2 || dtb_ver == DEV_TREE_VERSION_V3) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700268 board_data_count = (len_board_id / BOARD_ID_SIZE);
269 msm_data_count = (len_plat_id / PLAT_ID_SIZE);
Lijuan Gao9f152862014-08-18 13:45:24 +0800270 /* If dtb version is v2.0, the pmic_data_count will be <= 0 */
271 pmic_data_count = (len_pmic_id / PMIC_ID_SIZE);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700272
Lijuan Gao9f152862014-08-18 13:45:24 +0800273 /* If we are using dtb v3.0, then we have split board, msm & pmic data in the DTB
274 * If we are using dtb v2.0, then we have split board & msmdata in the DTB
275 */
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700276 board_data = (struct board_id *) malloc(sizeof(struct board_id) * (len_board_id / BOARD_ID_SIZE));
277 ASSERT(board_data);
278 platform_data = (struct plat_id *) malloc(sizeof(struct plat_id) * (len_plat_id / PLAT_ID_SIZE));
279 ASSERT(platform_data);
Lijuan Gao9f152862014-08-18 13:45:24 +0800280 if (dtb_ver == DEV_TREE_VERSION_V3) {
281 pmic_data = (struct pmic_id *) malloc(sizeof(struct pmic_id) * (len_pmic_id / PMIC_ID_SIZE));
282 ASSERT(pmic_data);
283 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700284 i = 0;
285
286 /* Extract board data from DTB */
Lijuan Gao9f152862014-08-18 13:45:24 +0800287 for(i = 0 ; i < board_data_count; i++) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700288 board_data[i].variant_id = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id);
289 board_data[i].platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->platform_subtype);
Lijuan Gao9f152862014-08-18 13:45:24 +0800290 /* For V2/V3 version of DTBs we have platform version field as part
291 * of variant ID, in such case the subtype will be mentioned as 0x0
292 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
293 * SS -- Subtype
294 * PM -- Platform major version
295 * Pm -- Platform minor version
296 * PH -- Platform hardware CDP/MTP
297 * In such case to make it compatible with LK algorithm move the subtype
298 * from variant_id to subtype field
299 */
300 if (board_data[i].platform_subtype == 0)
301 board_data[i].platform_subtype =
302 fdt32_to_cpu(((struct board_id *)board_prop)->variant_id) >> 0x18;
303
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700304 len_board_id -= sizeof(struct board_id);
305 board_prop += sizeof(struct board_id);
306 }
307
308 /* Extract platform data from DTB */
Lijuan Gao9f152862014-08-18 13:45:24 +0800309 for(i = 0 ; i < msm_data_count; i++) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700310 platform_data[i].platform_id = fdt32_to_cpu(((struct plat_id *)plat_prop)->platform_id);
311 platform_data[i].soc_rev = fdt32_to_cpu(((struct plat_id *)plat_prop)->soc_rev);
312 len_plat_id -= sizeof(struct plat_id);
313 plat_prop += sizeof(struct plat_id);
314 }
315
Lijuan Gao9f152862014-08-18 13:45:24 +0800316 if (dtb_ver == DEV_TREE_VERSION_V3 && pmic_prop) {
317 /* Extract pmic data from DTB */
318 for(i = 0 ; i < pmic_data_count; i++) {
319 pmic_data[i].pmic_version[0]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[0]);
320 pmic_data[i].pmic_version[1]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[1]);
321 pmic_data[i].pmic_version[2]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[2]);
322 pmic_data[i].pmic_version[3]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[3]);
323 len_pmic_id -= sizeof(struct pmic_id);
324 pmic_prop += sizeof(struct pmic_id);
325 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700326
Lijuan Gao9f152862014-08-18 13:45:24 +0800327 /* We need to merge board & platform data into dt entry structure */
328 num_entries = msm_data_count * board_data_count * pmic_data_count;
329 } else {
330 /* We need to merge board & platform data into dt entry structure */
331 num_entries = msm_data_count * board_data_count;
332 }
vijay kumar89d36d82014-06-30 19:32:18 +0530333
Lijuan Gao9f152862014-08-18 13:45:24 +0800334 if ((((uint64_t)msm_data_count * (uint64_t)board_data_count * (uint64_t)pmic_data_count) !=
335 msm_data_count * board_data_count * pmic_data_count) ||
336 (((uint64_t)msm_data_count * (uint64_t)board_data_count) != msm_data_count * board_data_count)) {
337
338 free(board_data);
339 free(platform_data);
340 if (pmic_data)
341 free(pmic_data);
342 if (model)
343 free(model);
344 return false;
345 }
346
347 dt_entry_array = (struct dt_entry*) malloc(sizeof(struct dt_entry) * num_entries);
348 ASSERT(dt_entry_array);
349
350 /* If we have '<X>; <Y>; <Z>' as platform data & '<A>; <B>; <C>' as board data.
351 * Then dt entry should look like
352 * <X ,A >;<X, B>;<X, C>;
353 * <Y ,A >;<Y, B>;<Y, C>;
354 * <Z ,A >;<Z, B>;<Z, C>;
355 */
356 i = 0;
357 k = 0;
358 n = 0;
359 for (i = 0; i < msm_data_count; i++) {
360 for (j = 0; j < board_data_count; j++) {
361 if (dtb_ver == DEV_TREE_VERSION_V3 && pmic_prop) {
362 for (n = 0; n < pmic_data_count; n++) {
363 dt_entry_array[k].platform_id = platform_data[i].platform_id;
364 dt_entry_array[k].soc_rev = platform_data[i].soc_rev;
365 dt_entry_array[k].variant_id = board_data[j].variant_id;
366 dt_entry_array[k].board_hw_subtype = board_data[j].platform_subtype;
367 dt_entry_array[k].pmic_rev[0]= pmic_data[n].pmic_version[0];
368 dt_entry_array[k].pmic_rev[1]= pmic_data[n].pmic_version[1];
369 dt_entry_array[k].pmic_rev[2]= pmic_data[n].pmic_version[2];
370 dt_entry_array[k].pmic_rev[3]= pmic_data[n].pmic_version[3];
371 dt_entry_array[k].offset = (uint32_t)dtb;
372 dt_entry_array[k].size = dtb_size;
373 k++;
374 }
375
376 } else {
377 dt_entry_array[k].platform_id = platform_data[i].platform_id;
378 dt_entry_array[k].soc_rev = platform_data[i].soc_rev;
379 dt_entry_array[k].variant_id = board_data[j].variant_id;
380 dt_entry_array[k].board_hw_subtype = board_data[j].platform_subtype;
381 dt_entry_array[k].pmic_rev[0]= board_pmic_target(0);
382 dt_entry_array[k].pmic_rev[1]= board_pmic_target(1);
383 dt_entry_array[k].pmic_rev[2]= board_pmic_target(2);
384 dt_entry_array[k].pmic_rev[3]= board_pmic_target(3);
385 dt_entry_array[k].offset = (uint32_t)dtb;
386 dt_entry_array[k].size = dtb_size;
vijay kumar89d36d82014-06-30 19:32:18 +0530387 k++;
388 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700389 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800390 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700391
Lijuan Gao9f152862014-08-18 13:45:24 +0800392 for (i=0 ;i < num_entries; i++) {
393 dprintf(SPEW, "Found an appended flattened device tree (%s - %u %u %u 0x%x)\n",
394 *model ? model : "unknown",
395 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 +0530396
Lijuan Gao9f152862014-08-18 13:45:24 +0800397 if (platform_dt_absolute_match(&(dt_entry_array[i]), dtb_list)) {
398 dprintf(SPEW, "Device tree exact match the board: <%u %u %u 0x%x> == <%u %u %u 0x%x>\n",
399 dt_entry_array[i].platform_id,
400 dt_entry_array[i].variant_id,
401 dt_entry_array[i].soc_rev,
402 dt_entry_array[i].board_hw_subtype,
403 board_platform_id(),
404 board_hardware_id(),
405 board_hardware_subtype(),
406 board_soc_version());
vijay kumar89d36d82014-06-30 19:32:18 +0530407
Lijuan Gao9f152862014-08-18 13:45:24 +0800408 } else {
409 dprintf(SPEW, "Device tree's msm_id doesn't match the board: <%u %u %u 0x%x> != <%u %u %u 0x%x>\n",
410 dt_entry_array[i].platform_id,
411 dt_entry_array[i].variant_id,
412 dt_entry_array[i].soc_rev,
413 dt_entry_array[i].board_hw_subtype,
414 board_platform_id(),
415 board_hardware_id(),
416 board_hardware_subtype(),
417 board_soc_version());
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700418 }
419 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800420
421 free(board_data);
422 free(platform_data);
423 if (pmic_data)
424 free(pmic_data);
425 free(dt_entry_array);
Dima Zavinc46f8382013-05-03 12:23:06 -0700426 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800427 if (model)
vijay kumar89d36d82014-06-30 19:32:18 +0530428 free(model);
Lijuan Gao9f152862014-08-18 13:45:24 +0800429 return true;
Dima Zavinc46f8382013-05-03 12:23:06 -0700430}
431
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800432/*
Dima Zavin77e41f32013-03-06 16:10:43 -0800433 * Will relocate the DTB to the tags addr if the device tree is found and return
434 * its address
435 *
436 * Arguments: kernel - Start address of the kernel loaded in RAM
437 * tags - Start address of the tags loaded in RAM
Channagoud Kadabi704cd562013-04-25 15:19:59 -0700438 * kernel_size - Size of the kernel in bytes
439 *
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800440 * Return Value: DTB address : If appended device tree is found
Dima Zavin77e41f32013-03-06 16:10:43 -0800441 * 'NULL' : Otherwise
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800442 */
Matthew Qinbb7923d2015-02-09 10:56:09 +0800443void *dev_tree_appended(void *kernel, uint32_t kernel_size, uint32_t dtb_offset, void *tags)
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800444{
Parth Dixit97e47bb2016-03-07 17:20:44 +0530445 uintptr_t kernel_end = (uintptr_t)kernel + kernel_size;
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800446 uint32_t app_dtb_offset = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800447 void *dtb = NULL;
Shashank Mittalc0f10282013-07-15 14:53:31 -0700448 void *bestmatch_tag = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800449 struct dt_entry *best_match_dt_entry = NULL;
Shashank Mittalc0f10282013-07-15 14:53:31 -0700450 uint32_t bestmatch_tag_size;
Lijuan Gao9f152862014-08-18 13:45:24 +0800451 struct dt_entry_node *dt_entry_queue = NULL;
452 struct dt_entry_node *dt_node_tmp1 = NULL;
453 struct dt_entry_node *dt_node_tmp2 = NULL;
454
Lijuan Gao9f152862014-08-18 13:45:24 +0800455 /* Initialize the dtb entry node*/
456 dt_entry_queue = (struct dt_entry_node *)
457 malloc(sizeof(struct dt_entry_node));
458
459 if (!dt_entry_queue) {
460 dprintf(CRITICAL, "Out of memory\n");
461 return NULL;
462 }
463 list_initialize(&dt_entry_queue->node);
464
Matthew Qinbb7923d2015-02-09 10:56:09 +0800465 if (dtb_offset)
466 app_dtb_offset = dtb_offset;
467 else
468 memcpy((void*) &app_dtb_offset, (void*) (kernel + DTB_OFFSET), sizeof(uint32_t));
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800469
vijay kumare2a5ea82014-06-25 12:24:14 +0530470 if (((uintptr_t)kernel + (uintptr_t)app_dtb_offset) < (uintptr_t)kernel) {
471 return NULL;
472 }
Parth Dixit97e47bb2016-03-07 17:20:44 +0530473 dtb = (void *)((uintptr_t)kernel + app_dtb_offset);
474
vijay kumare2a5ea82014-06-25 12:24:14 +0530475 while (((uintptr_t)dtb + sizeof(struct fdt_header)) < (uintptr_t)kernel_end) {
Dima Zavinc46f8382013-05-03 12:23:06 -0700476 struct fdt_header dtb_hdr;
477 uint32_t dtb_size;
Dima Zavin77e41f32013-03-06 16:10:43 -0800478
Dima Zavinc46f8382013-05-03 12:23:06 -0700479 /* the DTB could be unaligned, so extract the header,
480 * and operate on it separately */
481 memcpy(&dtb_hdr, dtb, sizeof(struct fdt_header));
482 if (fdt_check_header((const void *)&dtb_hdr) != 0 ||
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +0530483 fdt_check_header_ext((const void *)&dtb_hdr) != 0 ||
vijay kumare2a5ea82014-06-25 12:24:14 +0530484 ((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) < (uintptr_t)dtb) ||
485 ((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) > (uintptr_t)kernel_end))
Dima Zavinc46f8382013-05-03 12:23:06 -0700486 break;
487 dtb_size = fdt_totalsize(&dtb_hdr);
488
Lijuan Gao9f152862014-08-18 13:45:24 +0800489 dev_tree_compatible(dtb, dtb_size, dt_entry_queue);
Dima Zavinc46f8382013-05-03 12:23:06 -0700490
491 /* goto the next device tree if any */
492 dtb += dtb_size;
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800493 }
Dima Zavinc46f8382013-05-03 12:23:06 -0700494
Lijuan Gao9f152862014-08-18 13:45:24 +0800495 best_match_dt_entry = platform_dt_match_best(dt_entry_queue);
496 if (best_match_dt_entry){
497 bestmatch_tag = (void *)best_match_dt_entry->offset;
498 bestmatch_tag_size = best_match_dt_entry->size;
499 dprintf(INFO, "Best match DTB tags %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
500 best_match_dt_entry->platform_id, best_match_dt_entry->variant_id,
501 best_match_dt_entry->board_hw_subtype, best_match_dt_entry->soc_rev,
502 best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],
503 best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],
504 best_match_dt_entry->offset, best_match_dt_entry->size);
505 dprintf(INFO, "Using pmic info 0x%0x/0x%x/0x%x/0x%0x for device 0x%0x/0x%x/0x%x/0x%0x\n",
506 best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],
507 best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],
508 board_pmic_target(0), board_pmic_target(1),
509 board_pmic_target(2), board_pmic_target(3));
510 }
511 /* free queue's memory */
512 list_for_every_entry(&dt_entry_queue->node, dt_node_tmp1, dt_node, node) {
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -0800513 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +0800514 dt_entry_list_delete(dt_node_tmp1);
515 dt_node_tmp1 = dt_node_tmp2;
516 }
517
Shashank Mittalc0f10282013-07-15 14:53:31 -0700518 if(bestmatch_tag) {
Parth Dixitc2f0cb92016-03-10 10:40:14 +0530519 if (check_aboot_addr_range_overlap((uintptr_t)tags, bestmatch_tag_size)) {
520 dprintf(CRITICAL, "Tags addresses overlap with aboot addresses.\n");
521 return NULL;
522 }
Shashank Mittalc0f10282013-07-15 14:53:31 -0700523 memcpy(tags, bestmatch_tag, bestmatch_tag_size);
524 /* clear out the old DTB magic so kernel doesn't find it */
525 *((uint32_t *)(kernel + app_dtb_offset)) = 0;
526 return tags;
527 }
528
Dima Zavinc46f8382013-05-03 12:23:06 -0700529 dprintf(CRITICAL, "DTB offset is incorrect, kernel image does not have appended DTB\n");
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800530
David Ng59c4a782015-05-14 15:51:44 -0700531 dprintf(INFO, "Device info 0x%08x/%08x/0x%08x/%u, pmic 0x%0x/0x%x/0x%x/0x%0x\n",
532 board_platform_id(), board_soc_version(),
533 board_target_id(), board_hardware_subtype(),
534 board_pmic_target(0), board_pmic_target(1),
535 board_pmic_target(2), board_pmic_target(3));
Dima Zavin77e41f32013-03-06 16:10:43 -0800536 return NULL;
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800537}
538
Joel Kingaa335dc2013-06-03 16:11:08 -0700539/* Returns 0 if the device tree is valid. */
Deepa Dinamani87252952013-09-09 13:58:27 -0700540int dev_tree_validate(struct dt_table *table, unsigned int page_size, uint32_t *dt_hdr_size)
Joel Kingaa335dc2013-06-03 16:11:08 -0700541{
542 int dt_entry_size;
Channagoud Kadabid87c2772014-06-20 15:41:55 -0700543 uint64_t hdr_size;
Joel Kingaa335dc2013-06-03 16:11:08 -0700544
545 /* Validate the device tree table header */
546 if(table->magic != DEV_TREE_MAGIC) {
547 dprintf(CRITICAL, "ERROR: Bad magic in device tree table \n");
548 return -1;
549 }
550
551 if (table->version == DEV_TREE_VERSION_V1) {
552 dt_entry_size = sizeof(struct dt_entry_v1);
553 } else if (table->version == DEV_TREE_VERSION_V2) {
Lijuan Gao9f152862014-08-18 13:45:24 +0800554 dt_entry_size = sizeof(struct dt_entry_v2);
555 } else if (table->version == DEV_TREE_VERSION_V3) {
Joel Kingaa335dc2013-06-03 16:11:08 -0700556 dt_entry_size = sizeof(struct dt_entry);
557 } else {
558 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
559 table->version);
560 return -1;
561 }
562
Channagoud Kadabid87c2772014-06-20 15:41:55 -0700563 hdr_size = (uint64_t)table->num_entries * dt_entry_size + DEV_TREE_HEADER_SIZE;
564
Deepa Dinamani87252952013-09-09 13:58:27 -0700565 /* Roundup to page_size. */
566 hdr_size = ROUNDUP(hdr_size, page_size);
567
Channagoud Kadabid87c2772014-06-20 15:41:55 -0700568 if (hdr_size > UINT_MAX)
569 return -1;
570 else
571 *dt_hdr_size = hdr_size & UINT_MAX;
Joel Kingaa335dc2013-06-03 16:11:08 -0700572
573 return 0;
574}
575
Lijuan Gao9f152862014-08-18 13:45:24 +0800576static int platform_dt_absolute_match(struct dt_entry *cur_dt_entry, struct dt_entry_node *dt_list)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700577{
Lijuan Gaof8e95722014-12-23 03:03:12 -0500578 uint32_t cur_dt_hlos_ddr;
Lijuan Gao9f152862014-08-18 13:45:24 +0800579 uint32_t cur_dt_hw_platform;
580 uint32_t cur_dt_hw_subtype;
581 uint32_t cur_dt_msm_id;
582 dt_node *dt_node_tmp = NULL;
Channagoud Kadabi571193a2014-02-05 13:58:49 -0800583
Lijuan Gao9f152862014-08-18 13:45:24 +0800584 /* Platform-id
585 * bit no |31 24|23 16|15 0|
586 * |reserved|foundry-id|msm-id|
587 */
588 cur_dt_msm_id = (cur_dt_entry->platform_id & 0x0000ffff);
589 cur_dt_hw_platform = (cur_dt_entry->variant_id & 0x000000ff);
Lijuan Gao0621b862014-09-02 10:02:52 +0800590 cur_dt_hw_subtype = (cur_dt_entry->board_hw_subtype & 0xff);
Lijuan Gao9f152862014-08-18 13:45:24 +0800591
Lijuan Gaof8e95722014-12-23 03:03:12 -0500592 /* Determine the bits 10:8 to check the DT with the DDR Size */
593 cur_dt_hlos_ddr = (cur_dt_entry->board_hw_subtype & 0x700);
Channagoud Kadabi571193a2014-02-05 13:58:49 -0800594
Lijuan Gao9f152862014-08-18 13:45:24 +0800595 /* 1. must match the msm_id, platform_hw_id, platform_subtype and DDR size
596 * soc, board major/minor, pmic major/minor must less than board info
597 * 2. find the matched DTB then return 1
598 * 3. otherwise return 0
Maria Yu2e2d2c22013-07-03 19:20:33 +0800599 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800600 if((cur_dt_msm_id == (board_platform_id() & 0x0000ffff)) &&
601 (cur_dt_hw_platform == board_hardware_id()) &&
602 (cur_dt_hw_subtype == board_hardware_subtype()) &&
Lijuan Gaof8e95722014-12-23 03:03:12 -0500603 (cur_dt_hlos_ddr == (target_get_hlos_subtype() & 0x700)) &&
Lijuan Gao9f152862014-08-18 13:45:24 +0800604 (cur_dt_entry->soc_rev <= board_soc_version()) &&
605 ((cur_dt_entry->variant_id & 0x00ffff00) <= (board_target_id() & 0x00ffff00)) &&
606 ((cur_dt_entry->pmic_rev[0] & 0x00ffff00) <= (board_pmic_target(0) & 0x00ffff00)) &&
607 ((cur_dt_entry->pmic_rev[1] & 0x00ffff00) <= (board_pmic_target(1) & 0x00ffff00)) &&
608 ((cur_dt_entry->pmic_rev[2] & 0x00ffff00) <= (board_pmic_target(2) & 0x00ffff00)) &&
609 ((cur_dt_entry->pmic_rev[3] & 0x00ffff00) <= (board_pmic_target(3) & 0x00ffff00))) {
Maria Yu2e2d2c22013-07-03 19:20:33 +0800610
Lijuan Gao9f152862014-08-18 13:45:24 +0800611 dt_node_tmp = dt_entry_list_init();
612 memcpy((char*)dt_node_tmp->dt_entry_m,(char*)cur_dt_entry, sizeof(struct dt_entry));
613
614 dprintf(SPEW, "Add DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
615 dt_node_tmp->dt_entry_m->platform_id, dt_node_tmp->dt_entry_m->variant_id,
616 dt_node_tmp->dt_entry_m->board_hw_subtype, dt_node_tmp->dt_entry_m->soc_rev,
617 dt_node_tmp->dt_entry_m->pmic_rev[0], dt_node_tmp->dt_entry_m->pmic_rev[1],
618 dt_node_tmp->dt_entry_m->pmic_rev[2], dt_node_tmp->dt_entry_m->pmic_rev[3],
619 dt_node_tmp->dt_entry_m->offset, dt_node_tmp->dt_entry_m->size);
620
621 insert_dt_entry_in_queue(dt_list, dt_node_tmp);
622 return 1;
623 }
624 return 0;
625}
626
627static int platform_dt_absolute_compat_match(struct dt_entry_node *dt_list, uint32_t dtb_info) {
628 struct dt_entry_node *dt_node_tmp1 = NULL;
629 struct dt_entry_node *dt_node_tmp2 = NULL;
630 uint32_t current_info = 0;
631 uint32_t board_info = 0;
632 uint32_t best_info = 0;
633 uint32_t current_pmic_model[4] = {0, 0, 0, 0};
634 uint32_t board_pmic_model[4] = {0, 0, 0, 0};
635 uint32_t best_pmic_model[4] = {0, 0, 0, 0};
636 uint32_t delete_current_dt = 0;
637 uint32_t i;
638
639 /* start to select the exact entry
640 * default to exact match 0, if find current DTB entry info is the same as board info,
641 * then exact match board info.
642 */
643 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
644 if (!dt_node_tmp1){
645 dprintf(SPEW, "Current node is the end\n");
646 break;
647 }
648 switch(dtb_info) {
649 case DTB_FOUNDRY:
650 current_info = ((dt_node_tmp1->dt_entry_m->platform_id) & 0x00ff0000);
Channagoud Kadabi4cffc272014-10-29 11:23:26 -0700651 board_info = board_foundry_id() << 16;
Lijuan Gao9f152862014-08-18 13:45:24 +0800652 break;
653 case DTB_PMIC_MODEL:
654 for (i = 0; i < 4; i++) {
655 current_pmic_model[i] = (dt_node_tmp1->dt_entry_m->pmic_rev[i] & 0xff);
656 board_pmic_model[i] = (board_pmic_target(i) & 0xff);
657 }
658 break;
Lijuan Gaof8e95722014-12-23 03:03:12 -0500659 case DTB_PANEL_TYPE:
660 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0x1800);
661 board_info = (target_get_hlos_subtype() & 0x1800);
662 break;
663 case DTB_BOOT_DEVICE:
664 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0xf0000);
665 board_info = (target_get_hlos_subtype() & 0xf0000);
666 break;
Lijuan Gao9f152862014-08-18 13:45:24 +0800667 default:
668 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
669 dtb_info);
Maria Yuca51ee22013-06-27 21:45:24 +0800670 return 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800671 }
672
673 if (dtb_info == DTB_PMIC_MODEL) {
674 if ((current_pmic_model[0] == board_pmic_model[0]) &&
675 (current_pmic_model[1] == board_pmic_model[1]) &&
676 (current_pmic_model[2] == board_pmic_model[2]) &&
677 (current_pmic_model[3] == board_pmic_model[3])) {
678
679 for (i = 0; i < 4; i++) {
680 best_pmic_model[i] = current_pmic_model[i];
681 }
682 break;
683 }
684 } else {
685 if (current_info == board_info) {
686 best_info = current_info;
687 break;
688 }
689 }
690 }
691
692 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
693 if (!dt_node_tmp1){
694 dprintf(SPEW, "Current node is the end\n");
695 break;
696 }
697 switch(dtb_info) {
698 case DTB_FOUNDRY:
699 current_info = ((dt_node_tmp1->dt_entry_m->platform_id) & 0x00ff0000);
700 break;
701 case DTB_PMIC_MODEL:
702 for (i = 0; i < 4; i++) {
703 current_pmic_model[i] = (dt_node_tmp1->dt_entry_m->pmic_rev[i] & 0xff);
704 }
705 break;
Lijuan Gaof8e95722014-12-23 03:03:12 -0500706 case DTB_PANEL_TYPE:
707 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0x1800);
708 break;
709 case DTB_BOOT_DEVICE:
710 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0xf0000);
711 break;
Lijuan Gao9f152862014-08-18 13:45:24 +0800712 default:
713 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
714 dtb_info);
715 return 0;
716 }
717
718 if (dtb_info == DTB_PMIC_MODEL) {
719 if ((current_pmic_model[0] != best_pmic_model[0]) ||
720 (current_pmic_model[1] != best_pmic_model[1]) ||
721 (current_pmic_model[2] != best_pmic_model[2]) ||
722 (current_pmic_model[3] != best_pmic_model[3])) {
723
724 delete_current_dt = 1;
725 }
726 } else {
727 if (current_info != best_info) {
728 delete_current_dt = 1;
729 }
730 }
731
732 if (delete_current_dt) {
733 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
734 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
735 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
736 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
737 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
738 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
739
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -0800740 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +0800741 dt_entry_list_delete(dt_node_tmp1);
742 dt_node_tmp1 = dt_node_tmp2;
743 delete_current_dt = 0;
Maria Yuca51ee22013-06-27 21:45:24 +0800744 }
745 }
Maria Yuca51ee22013-06-27 21:45:24 +0800746
Maria Yu2e2d2c22013-07-03 19:20:33 +0800747 return 1;
Maria Yuca51ee22013-06-27 21:45:24 +0800748}
749
Lijuan Gao9f152862014-08-18 13:45:24 +0800750static int update_dtb_entry_node(struct dt_entry_node *dt_list, uint32_t dtb_info) {
751 struct dt_entry_node *dt_node_tmp1 = NULL;
752 struct dt_entry_node *dt_node_tmp2 = NULL;
753 uint32_t current_info = 0;
754 uint32_t board_info = 0;
755 uint32_t best_info = 0;
756
757 /* start to select the best entry*/
758 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
759 if (!dt_node_tmp1){
760 dprintf(SPEW, "Current node is the end\n");
761 break;
762 }
763 switch(dtb_info) {
764 case DTB_SOC:
765 current_info = dt_node_tmp1->dt_entry_m->soc_rev;
766 board_info = board_soc_version();
767 break;
768 case DTB_MAJOR_MINOR:
769 current_info = ((dt_node_tmp1->dt_entry_m->variant_id) & 0x00ffff00);
770 board_info = (board_target_id() & 0x00ffff00);
771 break;
772 case DTB_PMIC0:
773 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[0]) & 0x00ffff00);
774 board_info = (board_pmic_target(0) & 0x00ffff00);
775 break;
776 case DTB_PMIC1:
777 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[1]) & 0x00ffff00);
778 board_info = (board_pmic_target(1) & 0x00ffff00);
779 break;
780 case DTB_PMIC2:
781 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[2]) & 0x00ffff00);
782 board_info = (board_pmic_target(2) & 0x00ffff00);
783 break;
784 case DTB_PMIC3:
785 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[3]) & 0x00ffff00);
786 board_info = (board_pmic_target(3) & 0x00ffff00);
787 break;
788 default:
789 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
790 dtb_info);
791 return 0;
792 }
793
794 if (current_info == board_info) {
795 best_info = current_info;
796 break;
797 }
798 if ((current_info < board_info) && (current_info > best_info)) {
799 best_info = current_info;
800 }
801 if (current_info < best_info) {
802 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
803 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
804 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
805 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
806 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
807 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
808
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -0800809 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +0800810 dt_entry_list_delete(dt_node_tmp1);
811 dt_node_tmp1 = dt_node_tmp2;
812 }
813 }
814
815 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
816 if (!dt_node_tmp1){
817 dprintf(SPEW, "Current node is the end\n");
818 break;
819 }
820 switch(dtb_info) {
821 case DTB_SOC:
822 current_info = dt_node_tmp1->dt_entry_m->soc_rev;
823 break;
824 case DTB_MAJOR_MINOR:
825 current_info = ((dt_node_tmp1->dt_entry_m->variant_id) & 0x00ffff00);
826 break;
827 case DTB_PMIC0:
828 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[0]) & 0x00ffff00);
829 break;
830 case DTB_PMIC1:
831 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[1]) & 0x00ffff00);
832 break;
833 case DTB_PMIC2:
834 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[2]) & 0x00ffff00);
835 break;
836 case DTB_PMIC3:
837 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[3]) & 0x00ffff00);
838 break;
839 default:
840 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
841 dtb_info);
842 return 0;
843 }
844
845 if (current_info != best_info) {
846 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
847 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
848 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
849 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
850 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
851 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
852
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -0800853 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +0800854 dt_entry_list_delete(dt_node_tmp1);
855 dt_node_tmp1 = dt_node_tmp2;
856 }
857 }
858 return 1;
859}
860
861static struct dt_entry *platform_dt_match_best(struct dt_entry_node *dt_list)
862{
863 struct dt_entry_node *dt_node_tmp1 = NULL;
864
865 /* check Foundry id
866 * the foundry id must exact match board founddry id, this is compatibility check,
867 * if couldn't find the exact match from DTB, will exact match 0x0.
868 */
869 if (!platform_dt_absolute_compat_match(dt_list, DTB_FOUNDRY))
870 return NULL;
871
872 /* check PMIC model
873 * the PMIC model must exact match board PMIC model, this is compatibility check,
874 * if couldn't find the exact match from DTB, will exact match 0x0.
875 */
876 if (!platform_dt_absolute_compat_match(dt_list, DTB_PMIC_MODEL))
877 return NULL;
878
Lijuan Gaof8e95722014-12-23 03:03:12 -0500879 /* check panel type
880 * the panel type must exact match board panel type, this is compatibility check,
881 * if couldn't find the exact match from DTB, will exact match 0x0.
882 */
883 if (!platform_dt_absolute_compat_match(dt_list, DTB_PANEL_TYPE))
884 return NULL;
885
886 /* check boot device subtype
887 * the boot device subtype must exact match board boot device subtype, this is compatibility check,
888 * if couldn't find the exact match from DTB, will exact match 0x0.
889 */
890 if (!platform_dt_absolute_compat_match(dt_list, DTB_BOOT_DEVICE))
891 return NULL;
892
Lijuan Gao9f152862014-08-18 13:45:24 +0800893 /* check soc version
894 * the suitable soc version must less than or equal to board soc version
895 */
896 if (!update_dtb_entry_node(dt_list, DTB_SOC))
897 return NULL;
898
899 /*check major and minor version
900 * the suitable major&minor version must less than or equal to board major&minor version
901 */
902 if (!update_dtb_entry_node(dt_list, DTB_MAJOR_MINOR))
903 return NULL;
904
905 /*check pmic info
906 * the suitable pmic major&minor info must less than or equal to board pmic major&minor version
907 */
908 if (!update_dtb_entry_node(dt_list, DTB_PMIC0))
909 return NULL;
910 if (!update_dtb_entry_node(dt_list, DTB_PMIC1))
911 return NULL;
912 if (!update_dtb_entry_node(dt_list, DTB_PMIC2))
913 return NULL;
914 if (!update_dtb_entry_node(dt_list, DTB_PMIC3))
915 return NULL;
916
917 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
918 if (!dt_node_tmp1) {
919 dprintf(CRITICAL, "ERROR: Couldn't find the suitable DTB!\n");
920 return NULL;
921 }
922 if (dt_node_tmp1->dt_entry_m)
923 return dt_node_tmp1->dt_entry_m;
924 }
925
926 return NULL;
927}
928
929/* Function to obtain the index information for the correct device tree
930 * based on the platform data.
931 * If a matching device tree is found, the information is returned in the
932 * "dt_entry_info" out parameter and a function value of 0 is returned, otherwise
933 * a non-zero function value is returned.
934 */
935int dev_tree_get_entry_info(struct dt_table *table, struct dt_entry *dt_entry_info)
Maria Yuca51ee22013-06-27 21:45:24 +0800936{
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700937 uint32_t i;
Lijuan Gao9f152862014-08-18 13:45:24 +0800938 unsigned char *table_ptr = NULL;
Joel Kingaa335dc2013-06-03 16:11:08 -0700939 struct dt_entry dt_entry_buf_1;
Lijuan Gao9f152862014-08-18 13:45:24 +0800940 struct dt_entry *cur_dt_entry = NULL;
941 struct dt_entry *best_match_dt_entry = NULL;
942 struct dt_entry_v1 *dt_entry_v1 = NULL;
943 struct dt_entry_v2 *dt_entry_v2 = NULL;
944 struct dt_entry_node *dt_entry_queue = NULL;
945 struct dt_entry_node *dt_node_tmp1 = NULL;
946 struct dt_entry_node *dt_node_tmp2 = NULL;
Maria Yu2e2d2c22013-07-03 19:20:33 +0800947 uint32_t found = 0;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700948
Joel Kingaa335dc2013-06-03 16:11:08 -0700949 if (!dt_entry_info) {
950 dprintf(CRITICAL, "ERROR: Bad parameter passed to %s \n",
951 __func__);
952 return -1;
953 }
954
955 table_ptr = (unsigned char *)table + DEV_TREE_HEADER_SIZE;
956 cur_dt_entry = &dt_entry_buf_1;
957 best_match_dt_entry = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800958 dt_entry_queue = (struct dt_entry_node *)
959 malloc(sizeof(struct dt_entry_node));
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700960
Lijuan Gao9f152862014-08-18 13:45:24 +0800961 if (!dt_entry_queue) {
962 dprintf(CRITICAL, "Out of memory\n");
963 return -1;
964 }
965
966 list_initialize(&dt_entry_queue->node);
967 dprintf(INFO, "DTB Total entry: %d, DTB version: %d\n", table->num_entries, table->version);
Maria Yu2e2d2c22013-07-03 19:20:33 +0800968 for(i = 0; found == 0 && i < table->num_entries; i++)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700969 {
Joel Kingaa335dc2013-06-03 16:11:08 -0700970 memset(cur_dt_entry, 0, sizeof(struct dt_entry));
971 switch(table->version) {
972 case DEV_TREE_VERSION_V1:
973 dt_entry_v1 = (struct dt_entry_v1 *)table_ptr;
974 cur_dt_entry->platform_id = dt_entry_v1->platform_id;
975 cur_dt_entry->variant_id = dt_entry_v1->variant_id;
976 cur_dt_entry->soc_rev = dt_entry_v1->soc_rev;
Lijuan Gao9f152862014-08-18 13:45:24 +0800977 cur_dt_entry->board_hw_subtype = (dt_entry_v1->variant_id >> 0x18);
978 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
979 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
980 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
981 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
Joel Kingaa335dc2013-06-03 16:11:08 -0700982 cur_dt_entry->offset = dt_entry_v1->offset;
983 cur_dt_entry->size = dt_entry_v1->size;
984 table_ptr += sizeof(struct dt_entry_v1);
985 break;
986 case DEV_TREE_VERSION_V2:
Lijuan Gao9f152862014-08-18 13:45:24 +0800987 dt_entry_v2 = (struct dt_entry_v2*)table_ptr;
988 cur_dt_entry->platform_id = dt_entry_v2->platform_id;
989 cur_dt_entry->variant_id = dt_entry_v2->variant_id;
990 cur_dt_entry->soc_rev = dt_entry_v2->soc_rev;
991 /* For V2 version of DTBs we have platform version field as part
992 * of variant ID, in such case the subtype will be mentioned as 0x0
993 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
994 * SS -- Subtype
995 * PM -- Platform major version
996 * Pm -- Platform minor version
997 * PH -- Platform hardware CDP/MTP
998 * In such case to make it compatible with LK algorithm move the subtype
999 * from variant_id to subtype field
1000 */
1001 if (dt_entry_v2->board_hw_subtype == 0)
1002 cur_dt_entry->board_hw_subtype = (cur_dt_entry->variant_id >> 0x18);
1003 else
1004 cur_dt_entry->board_hw_subtype = dt_entry_v2->board_hw_subtype;
1005 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
1006 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
1007 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
1008 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
1009 cur_dt_entry->offset = dt_entry_v2->offset;
1010 cur_dt_entry->size = dt_entry_v2->size;
1011 table_ptr += sizeof(struct dt_entry_v2);
1012 break;
1013 case DEV_TREE_VERSION_V3:
Joel Kingaa335dc2013-06-03 16:11:08 -07001014 memcpy(cur_dt_entry, (struct dt_entry *)table_ptr,
1015 sizeof(struct dt_entry));
Lijuan Gao9f152862014-08-18 13:45:24 +08001016 /* For V3 version of DTBs we have platform version field as part
1017 * of variant ID, in such case the subtype will be mentioned as 0x0
1018 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
1019 * SS -- Subtype
1020 * PM -- Platform major version
1021 * Pm -- Platform minor version
1022 * PH -- Platform hardware CDP/MTP
1023 * In such case to make it compatible with LK algorithm move the subtype
1024 * from variant_id to subtype field
1025 */
1026 if (cur_dt_entry->board_hw_subtype == 0)
1027 cur_dt_entry->board_hw_subtype = (cur_dt_entry->variant_id >> 0x18);
1028
Joel Kingaa335dc2013-06-03 16:11:08 -07001029 table_ptr += sizeof(struct dt_entry);
1030 break;
1031 default:
1032 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
1033 table->version);
Lijuan Gao9f152862014-08-18 13:45:24 +08001034 free(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001035 return -1;
1036 }
1037
Lijuan Gao9f152862014-08-18 13:45:24 +08001038 /* DTBs must match the platform_id, platform_hw_id, platform_subtype and DDR size.
1039 * The satisfactory DTBs are stored in dt_entry_queue
1040 */
1041 platform_dt_absolute_match(cur_dt_entry, dt_entry_queue);
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -08001042
Lijuan Gao9f152862014-08-18 13:45:24 +08001043 }
1044 best_match_dt_entry = platform_dt_match_best(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001045 if (best_match_dt_entry) {
1046 *dt_entry_info = *best_match_dt_entry;
Maria Yu2e2d2c22013-07-03 19:20:33 +08001047 found = 1;
1048 }
1049
1050 if (found != 0) {
Sundarajan Srinivasan763c0db2014-05-20 17:08:36 -07001051 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 -07001052 dt_entry_info->platform_id, dt_entry_info->soc_rev,
1053 dt_entry_info->variant_id, dt_entry_info->board_hw_subtype,
Lijuan Gao9f152862014-08-18 13:45:24 +08001054 board_platform_id(), board_soc_version(),
1055 board_target_id(), board_hardware_subtype());
1056 if (dt_entry_info->pmic_rev[0] == 0 && dt_entry_info->pmic_rev[0] == 0 &&
1057 dt_entry_info->pmic_rev[0] == 0 && dt_entry_info->pmic_rev[0] == 0) {
1058 dprintf(SPEW, "No maintain pmic info in DTB, device pmic info is 0x%0x/0x%x/0x%x/0x%0x\n",
1059 board_pmic_target(0), board_pmic_target(1),
1060 board_pmic_target(2), board_pmic_target(3));
1061 } else {
1062 dprintf(INFO, "Using pmic info 0x%0x/0x%x/0x%x/0x%0x for device 0x%0x/0x%x/0x%x/0x%0x\n",
1063 dt_entry_info->pmic_rev[0], dt_entry_info->pmic_rev[1],
1064 dt_entry_info->pmic_rev[2], dt_entry_info->pmic_rev[3],
1065 board_pmic_target(0), board_pmic_target(1),
1066 board_pmic_target(2), board_pmic_target(3));
1067 }
Joel Kingaa335dc2013-06-03 16:11:08 -07001068 return 0;
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -08001069 }
1070
Lijuan Gao9f152862014-08-18 13:45:24 +08001071 dprintf(CRITICAL, "ERROR: Unable to find suitable device tree for device (%u/0x%08x/0x%08x/%u)\n",
1072 board_platform_id(), board_soc_version(),
1073 board_target_id(), board_hardware_subtype());
1074
1075 list_for_every_entry(&dt_entry_queue->node, dt_node_tmp1, dt_node, node) {
1076 /* free node memory */
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001077 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001078 dt_entry_list_delete(dt_node_tmp1);
1079 dt_node_tmp1 = dt_node_tmp2;
1080 }
1081 free(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001082 return -1;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001083}
1084
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001085/* Function to add the first RAM partition info to the device tree.
1086 * Note: The function replaces the reg property in the "/memory" node
1087 * with the addr and size provided.
1088 */
1089int dev_tree_add_first_mem_info(uint32_t *fdt, uint32_t offset, uint32_t addr, uint32_t size)
1090{
1091 int ret;
1092
1093 ret = fdt_setprop_u32(fdt, offset, "reg", addr);
1094
1095 if (ret)
1096 {
1097 dprintf(CRITICAL, "Failed to add the memory information addr: %d\n",
1098 ret);
1099 }
1100
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001101 ret = fdt_appendprop_u32(fdt, offset, "reg", size);
1102
1103 if (ret)
1104 {
1105 dprintf(CRITICAL, "Failed to add the memory information size: %d\n",
1106 ret);
1107 }
1108
1109 return ret;
1110}
1111
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001112static 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 -07001113{
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001114 int len;
1115 uint32_t *valp;
1116 int ret;
1117 uint32_t offset;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001118
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001119 mem_node->offset = mem_node_offset;
1120
1121 /* Get offset of the root node */
1122 ret = fdt_path_offset(fdt, "/");
1123 if (ret < 0)
1124 {
1125 dprintf(CRITICAL, "Could not find memory node.\n");
1126 return ret;
1127 }
1128
1129 offset = ret;
1130
1131 /* Find the #address-cells size. */
1132 valp = (uint32_t*)fdt_getprop(fdt, offset, "#address-cells", &len);
Lijuan Gaoae0927b2014-07-18 17:16:16 +08001133 if (len <= 0 || !valp)
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001134 {
1135 if (len == -FDT_ERR_NOTFOUND)
1136 {
1137 /* Property not found.
1138 * Assume standard sizes.
1139 */
1140 mem_node->addr_cell_size = 2;
1141 dprintf(CRITICAL, "Using default #addr_cell_size: %u\n", mem_node->addr_cell_size);
1142 }
1143 else
1144 {
1145 dprintf(CRITICAL, "Error finding the #address-cells property\n");
1146 return len;
1147 }
1148 }
1149 else
1150 mem_node->addr_cell_size = fdt32_to_cpu(*valp);
1151
1152 /* Find the #size-cells size. */
1153 valp = (uint32_t*)fdt_getprop(fdt, offset, "#size-cells", &len);
Lijuan Gaoae0927b2014-07-18 17:16:16 +08001154 if (len <= 0 || !valp)
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001155 {
1156 if (len == -FDT_ERR_NOTFOUND)
1157 {
1158 /* Property not found.
1159 * Assume standard sizes.
1160 */
1161 mem_node->size_cell_size = 1;
1162 dprintf(CRITICAL, "Using default #size_cell_size: %u\n", mem_node->size_cell_size);
1163 }
1164 else
1165 {
1166 dprintf(CRITICAL, "Error finding the #size-cells property\n");
1167 return len;
1168 }
1169 }
1170 else
1171 mem_node->size_cell_size = fdt32_to_cpu(*valp);
1172
1173 return 0;
1174}
1175
1176static void dev_tree_update_memory_node(uint32_t offset)
1177{
1178 mem_node.offset = offset;
1179 mem_node.addr_cell_size = 1;
1180 mem_node.size_cell_size = 1;
1181}
1182
1183/* Function to add the subsequent RAM partition info to the device tree. */
1184int dev_tree_add_mem_info(void *fdt, uint32_t offset, uint64_t addr, uint64_t size)
1185{
1186 int ret = 0;
1187
1188 if(smem_get_ram_ptable_version() >= 1)
1189 {
1190 ret = dev_tree_query_memory_cell_sizes(fdt, &mem_node, offset);
1191 if (ret < 0)
1192 {
1193 dprintf(CRITICAL, "Could not find #address-cells and #size-cells properties: ret %d\n", ret);
1194 return ret;
1195 }
1196
1197 }
1198 else
1199 {
1200 dev_tree_update_memory_node(offset);
1201 }
1202
1203 if (!(mem_node.mem_info_cnt))
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001204 {
1205 /* Replace any other reg prop in the memory node. */
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001206
1207 /* cell_size is the number of 32 bit words used to represent an address/length in the device tree.
1208 * memory node in DT can be either 32-bit(cell-size = 1) or 64-bit(cell-size = 2).So when updating
1209 * the memory node in the device tree, we write one word or two words based on cell_size = 1 or 2.
1210 */
1211
1212 if(mem_node.addr_cell_size == 2)
1213 {
1214 ret = fdt_setprop_u32(fdt, mem_node.offset, "reg", addr >> 32);
1215 if(ret)
1216 {
1217 dprintf(CRITICAL, "ERROR: Could not set prop reg for memory node\n");
1218 return ret;
1219 }
1220
1221 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1222 if(ret)
1223 {
1224 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1225 return ret;
1226 }
1227 }
1228 else
1229 {
1230 ret = fdt_setprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1231 if(ret)
1232 {
1233 dprintf(CRITICAL, "ERROR: Could not set prop reg for memory node\n");
1234 return ret;
1235 }
1236 }
1237
1238 mem_node.mem_info_cnt = 1;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001239 }
1240 else
1241 {
1242 /* Append the mem info to the reg prop for subsequent nodes. */
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001243 if(mem_node.addr_cell_size == 2)
1244 {
1245 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", addr >> 32);
1246 if(ret)
1247 {
1248 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1249 return ret;
1250 }
1251 }
1252
1253 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1254 if(ret)
1255 {
1256 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1257 return ret;
1258 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001259 }
1260
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001261 if(mem_node.size_cell_size == 2)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001262 {
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001263 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", size>>32);
1264 if(ret)
1265 {
1266 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1267 return ret;
1268 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001269 }
1270
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001271 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)size);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001272
1273 if (ret)
1274 {
1275 dprintf(CRITICAL, "Failed to add the memory information size: %d\n",
1276 ret);
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001277 return ret;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001278 }
1279
1280 return ret;
1281}
1282
1283/* Top level function that updates the device tree. */
1284int update_device_tree(void *fdt, const char *cmdline,
1285 void *ramdisk, uint32_t ramdisk_size)
1286{
1287 int ret = 0;
1288 uint32_t offset;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001289
1290 /* Check the device tree header */
Vijay Kumar Pendoti0f249e32016-03-18 18:17:01 +05301291 ret = fdt_check_header(fdt) || fdt_check_header_ext(fdt);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001292 if (ret)
1293 {
1294 dprintf(CRITICAL, "Invalid device tree header \n");
1295 return ret;
1296 }
1297
P.V. Phani Kumar9cd95102016-03-09 12:35:23 +05301298 if (check_aboot_addr_range_overlap((uint32_t)fdt,
1299 (fdt_totalsize(fdt) + DTB_PAD_SIZE))) {
1300 dprintf(CRITICAL, "Error: Fdt addresses overlap with aboot addresses.\n");
1301 return ret;
1302 }
1303
Deepa Dinamani1c970732013-04-19 14:23:01 -07001304 /* Add padding to make space for new nodes and properties. */
1305 ret = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + DTB_PAD_SIZE);
1306 if (ret!= 0)
1307 {
1308 dprintf(CRITICAL, "Failed to move/resize dtb buffer: %d\n", ret);
1309 return ret;
1310 }
1311
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001312 /* Get offset of the memory node */
1313 ret = fdt_path_offset(fdt, "/memory");
1314 if (ret < 0)
1315 {
1316 dprintf(CRITICAL, "Could not find memory node.\n");
1317 return ret;
1318 }
1319
1320 offset = ret;
1321
1322 ret = target_dev_tree_mem(fdt, offset);
1323 if(ret)
1324 {
1325 dprintf(CRITICAL, "ERROR: Cannot update memory node\n");
1326 return ret;
1327 }
1328
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001329 /* Get offset of the chosen node */
1330 ret = fdt_path_offset(fdt, "/chosen");
1331 if (ret < 0)
1332 {
1333 dprintf(CRITICAL, "Could not find chosen node.\n");
1334 return ret;
1335 }
1336
1337 offset = ret;
Maria Yuabde9542014-07-07 14:49:34 +08001338 if (cmdline)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001339 {
Maria Yuabde9542014-07-07 14:49:34 +08001340 /* Adding the cmdline to the chosen node */
1341 ret = fdt_appendprop_string(fdt, offset, (const char*)"bootargs", (const void*)cmdline);
1342 if (ret)
1343 {
1344 dprintf(CRITICAL, "ERROR: Cannot update chosen node [bootargs]\n");
1345 return ret;
1346 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001347 }
1348
Joonwoo Parka5b5f492014-02-13 18:24:48 -08001349 if (ramdisk_size) {
1350 /* Adding the initrd-start to the chosen node */
1351 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-start",
1352 (uint32_t)ramdisk);
1353 if (ret)
1354 {
1355 dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-start]\n");
1356 return ret;
1357 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001358
Joonwoo Parka5b5f492014-02-13 18:24:48 -08001359 /* Adding the initrd-end to the chosen node */
1360 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-end",
1361 ((uint32_t)ramdisk + ramdisk_size));
1362 if (ret)
1363 {
1364 dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-end]\n");
1365 return ret;
1366 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001367 }
1368
1369 fdt_pack(fdt);
1370
Channagoud Kadabiffaea422014-12-05 15:45:41 -08001371#if ENABLE_PARTIAL_GOODS_SUPPORT
1372 update_partial_goods_dtb_nodes(fdt);
1373#endif
1374
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001375 return ret;
1376}