blob: 5cd657619f5aa471ddb23323aec042afc25af5ed [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 */
61extern int check_aboot_addr_range_overlap(uint32_t start, uint32_t size);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -070062
Shashank Mittalc0f10282013-07-15 14:53:31 -070063/* Returns soc version if platform id and hardware id matches
64 otherwise return 0xFFFFFFFF */
65#define INVALID_SOC_REV_ID 0XFFFFFFFF
Lijuan Gao9f152862014-08-18 13:45:24 +080066
67/* Add function to allocate dt entry list, used for recording
68* the entry which conform to platform_dt_absolute_match()
69*/
70static struct dt_entry_node *dt_entry_list_init(void)
71{
72 struct dt_entry_node *dt_node_member = NULL;
73
74 dt_node_member = (struct dt_entry_node *)
75 malloc(sizeof(struct dt_entry_node));
76
77 ASSERT(dt_node_member);
78
79 list_clear_node(&dt_node_member->node);
80 dt_node_member->dt_entry_m = (struct dt_entry *)
81 malloc(sizeof(struct dt_entry));
82 ASSERT(dt_node_member->dt_entry_m);
83
84 memset(dt_node_member->dt_entry_m ,0 ,sizeof(struct dt_entry));
85 return dt_node_member;
86}
87
88static void insert_dt_entry_in_queue(struct dt_entry_node *dt_list, struct dt_entry_node *dt_node_member)
89{
90 list_add_tail(&dt_list->node, &dt_node_member->node);
91}
92
93static void dt_entry_list_delete(struct dt_entry_node *dt_node_member)
94{
95 if (list_in_list(&dt_node_member->node)) {
96 list_delete(&dt_node_member->node);
97 free(dt_node_member->dt_entry_m);
98 free(dt_node_member);
99 }
100}
101
102static int dev_tree_compatible(void *dtb, uint32_t dtb_size, struct dt_entry_node *dtb_list)
Dima Zavinc46f8382013-05-03 12:23:06 -0700103{
104 int root_offset;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700105 const void *prop = NULL;
106 const char *plat_prop = NULL;
107 const char *board_prop = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800108 const char *pmic_prop = NULL;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700109 char *model = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800110 struct dt_entry *cur_dt_entry;
111 struct dt_entry *dt_entry_array = NULL;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700112 struct board_id *board_data = NULL;
113 struct plat_id *platform_data = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800114 struct pmic_id *pmic_data = NULL;
Dima Zavinc46f8382013-05-03 12:23:06 -0700115 int len;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700116 int len_board_id;
117 int len_plat_id;
118 int min_plat_id_len = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800119 int len_pmic_id;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700120 uint32_t dtb_ver;
121 uint32_t num_entries = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800122 uint32_t i, j, k, n;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700123 uint32_t msm_data_count;
124 uint32_t board_data_count;
Lijuan Gao9f152862014-08-18 13:45:24 +0800125 uint32_t pmic_data_count;
Dima Zavinc46f8382013-05-03 12:23:06 -0700126
127 root_offset = fdt_path_offset(dtb, "/");
128 if (root_offset < 0)
129 return false;
130
131 prop = fdt_getprop(dtb, root_offset, "model", &len);
132 if (prop && len > 0) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700133 model = (char *) malloc(sizeof(char) * len);
134 ASSERT(model);
135 strlcpy(model, prop, len);
Dima Zavinc46f8382013-05-03 12:23:06 -0700136 } else {
vijay kumar89d36d82014-06-30 19:32:18 +0530137 dprintf(INFO, "model does not exist in device tree\n");
Dima Zavinc46f8382013-05-03 12:23:06 -0700138 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800139 /* Find the pmic-id prop from DTB , if pmic-id is present then
140 * the DTB is version 3, otherwise find the board-id prop from DTB ,
141 * if board-id is present then the DTB is version 2 */
142 pmic_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,pmic-id", &len_pmic_id);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700143 board_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,board-id", &len_board_id);
Lijuan Gao9f152862014-08-18 13:45:24 +0800144 if (pmic_prop && (len_pmic_id > 0) && board_prop && (len_board_id > 0)) {
145 if ((len_pmic_id % PMIC_ID_SIZE) || (len_board_id % BOARD_ID_SIZE))
146 {
147 dprintf(CRITICAL, "qcom,pmic-id(%d) or qcom,board-id(%d) in device tree is not a multiple of (%d %d)\n",
148 len_pmic_id, len_board_id, PMIC_ID_SIZE, BOARD_ID_SIZE);
149 return false;
150 }
151 dtb_ver = DEV_TREE_VERSION_V3;
152 min_plat_id_len = PLAT_ID_SIZE;
153 } else if (board_prop && len_board_id > 0) {
vijay kumar89d36d82014-06-30 19:32:18 +0530154 if (len_board_id % BOARD_ID_SIZE)
155 {
156 dprintf(CRITICAL, "qcom,board-id in device tree is (%d) not a multiple of (%d)\n",
157 len_board_id, BOARD_ID_SIZE);
158 return false;
159 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700160 dtb_ver = DEV_TREE_VERSION_V2;
161 min_plat_id_len = PLAT_ID_SIZE;
Lijuan Gao9f152862014-08-18 13:45:24 +0800162 } else {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700163 dtb_ver = DEV_TREE_VERSION_V1;
164 min_plat_id_len = DT_ENTRY_V1_SIZE;
165 }
166
167 /* Get the msm-id prop from DTB */
168 plat_prop = (const char *)fdt_getprop(dtb, root_offset, "qcom,msm-id", &len_plat_id);
169 if (!plat_prop || len_plat_id <= 0) {
Dima Zavinc46f8382013-05-03 12:23:06 -0700170 dprintf(INFO, "qcom,msm-id entry not found\n");
171 return false;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700172 } else if (len_plat_id % min_plat_id_len) {
173 dprintf(INFO, "qcom,msm-id in device tree is (%d) not a multiple of (%d)\n",
174 len_plat_id, min_plat_id_len);
Dima Zavinc46f8382013-05-03 12:23:06 -0700175 return false;
176 }
Dima Zavinc46f8382013-05-03 12:23:06 -0700177
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700178 /*
179 * If DTB version is '1' look for <x y z> pair in the DTB
180 * x: platform_id
181 * y: variant_id
182 * z: SOC rev
183 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800184 if (dtb_ver == DEV_TREE_VERSION_V1) {
185 cur_dt_entry = (struct dt_entry *)
186 malloc(sizeof(struct dt_entry));
Dima Zavinc46f8382013-05-03 12:23:06 -0700187
Lijuan Gao9f152862014-08-18 13:45:24 +0800188 if (!cur_dt_entry) {
189 dprintf(CRITICAL, "Out of memory\n");
190 return false;
191 }
192 memset(cur_dt_entry, 0, sizeof(struct dt_entry));
193
194 while (len_plat_id) {
195 cur_dt_entry->platform_id = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->platform_id);
196 cur_dt_entry->variant_id = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->variant_id);
197 cur_dt_entry->soc_rev = fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->soc_rev);
198 cur_dt_entry->board_hw_subtype =
199 fdt32_to_cpu(((const struct dt_entry_v1 *)plat_prop)->variant_id) >> 0x18;
200 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
201 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
202 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
203 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
204 cur_dt_entry->offset = (uint32_t)dtb;
205 cur_dt_entry->size = dtb_size;
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700206
207 dprintf(SPEW, "Found an appended flattened device tree (%s - %u %u 0x%x)\n",
Lijuan Gao9f152862014-08-18 13:45:24 +0800208 *model ? model : "unknown",
209 cur_dt_entry->platform_id, cur_dt_entry->variant_id, cur_dt_entry->soc_rev);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700210
Lijuan Gao9f152862014-08-18 13:45:24 +0800211 if (platform_dt_absolute_match(cur_dt_entry, dtb_list)) {
212 dprintf(SPEW, "Device tree exact match the board: <%u %u 0x%x> != <%u %u 0x%x>\n",
213 cur_dt_entry->platform_id,
214 cur_dt_entry->variant_id,
215 cur_dt_entry->soc_rev,
216 board_platform_id(),
217 board_hardware_id(),
218 board_soc_version());
219
220 } else {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700221 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 +0800222 cur_dt_entry->platform_id,
223 cur_dt_entry->variant_id,
224 cur_dt_entry->soc_rev,
225 board_platform_id(),
226 board_hardware_id(),
227 board_soc_version());
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700228 plat_prop += DT_ENTRY_V1_SIZE;
229 len_plat_id -= DT_ENTRY_V1_SIZE;
230 continue;
231 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700232 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800233 free(cur_dt_entry);
234
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700235 }
236 /*
Lijuan Gao9f152862014-08-18 13:45:24 +0800237 * If DTB Version is '3' then we have split DTB with board & msm data & pmic
238 * populated saperately in board-id & msm-id & pmic-id prop respectively.
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700239 * Extract the data & prepare a look up table
240 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800241 else if (dtb_ver == DEV_TREE_VERSION_V2 || dtb_ver == DEV_TREE_VERSION_V3) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700242 board_data_count = (len_board_id / BOARD_ID_SIZE);
243 msm_data_count = (len_plat_id / PLAT_ID_SIZE);
Lijuan Gao9f152862014-08-18 13:45:24 +0800244 /* If dtb version is v2.0, the pmic_data_count will be <= 0 */
245 pmic_data_count = (len_pmic_id / PMIC_ID_SIZE);
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700246
Lijuan Gao9f152862014-08-18 13:45:24 +0800247 /* If we are using dtb v3.0, then we have split board, msm & pmic data in the DTB
248 * If we are using dtb v2.0, then we have split board & msmdata in the DTB
249 */
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700250 board_data = (struct board_id *) malloc(sizeof(struct board_id) * (len_board_id / BOARD_ID_SIZE));
251 ASSERT(board_data);
252 platform_data = (struct plat_id *) malloc(sizeof(struct plat_id) * (len_plat_id / PLAT_ID_SIZE));
253 ASSERT(platform_data);
Lijuan Gao9f152862014-08-18 13:45:24 +0800254 if (dtb_ver == DEV_TREE_VERSION_V3) {
255 pmic_data = (struct pmic_id *) malloc(sizeof(struct pmic_id) * (len_pmic_id / PMIC_ID_SIZE));
256 ASSERT(pmic_data);
257 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700258 i = 0;
259
260 /* Extract board data from DTB */
Lijuan Gao9f152862014-08-18 13:45:24 +0800261 for(i = 0 ; i < board_data_count; i++) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700262 board_data[i].variant_id = fdt32_to_cpu(((struct board_id *)board_prop)->variant_id);
263 board_data[i].platform_subtype = fdt32_to_cpu(((struct board_id *)board_prop)->platform_subtype);
Lijuan Gao9f152862014-08-18 13:45:24 +0800264 /* For V2/V3 version of DTBs we have platform version field as part
265 * of variant ID, in such case the subtype will be mentioned as 0x0
266 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
267 * SS -- Subtype
268 * PM -- Platform major version
269 * Pm -- Platform minor version
270 * PH -- Platform hardware CDP/MTP
271 * In such case to make it compatible with LK algorithm move the subtype
272 * from variant_id to subtype field
273 */
274 if (board_data[i].platform_subtype == 0)
275 board_data[i].platform_subtype =
276 fdt32_to_cpu(((struct board_id *)board_prop)->variant_id) >> 0x18;
277
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700278 len_board_id -= sizeof(struct board_id);
279 board_prop += sizeof(struct board_id);
280 }
281
282 /* Extract platform data from DTB */
Lijuan Gao9f152862014-08-18 13:45:24 +0800283 for(i = 0 ; i < msm_data_count; i++) {
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700284 platform_data[i].platform_id = fdt32_to_cpu(((struct plat_id *)plat_prop)->platform_id);
285 platform_data[i].soc_rev = fdt32_to_cpu(((struct plat_id *)plat_prop)->soc_rev);
286 len_plat_id -= sizeof(struct plat_id);
287 plat_prop += sizeof(struct plat_id);
288 }
289
Lijuan Gao9f152862014-08-18 13:45:24 +0800290 if (dtb_ver == DEV_TREE_VERSION_V3 && pmic_prop) {
291 /* Extract pmic data from DTB */
292 for(i = 0 ; i < pmic_data_count; i++) {
293 pmic_data[i].pmic_version[0]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[0]);
294 pmic_data[i].pmic_version[1]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[1]);
295 pmic_data[i].pmic_version[2]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[2]);
296 pmic_data[i].pmic_version[3]= fdt32_to_cpu(((struct pmic_id *)pmic_prop)->pmic_version[3]);
297 len_pmic_id -= sizeof(struct pmic_id);
298 pmic_prop += sizeof(struct pmic_id);
299 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700300
Lijuan Gao9f152862014-08-18 13:45:24 +0800301 /* We need to merge board & platform data into dt entry structure */
302 num_entries = msm_data_count * board_data_count * pmic_data_count;
303 } else {
304 /* We need to merge board & platform data into dt entry structure */
305 num_entries = msm_data_count * board_data_count;
306 }
vijay kumar89d36d82014-06-30 19:32:18 +0530307
Lijuan Gao9f152862014-08-18 13:45:24 +0800308 if ((((uint64_t)msm_data_count * (uint64_t)board_data_count * (uint64_t)pmic_data_count) !=
309 msm_data_count * board_data_count * pmic_data_count) ||
310 (((uint64_t)msm_data_count * (uint64_t)board_data_count) != msm_data_count * board_data_count)) {
311
312 free(board_data);
313 free(platform_data);
314 if (pmic_data)
315 free(pmic_data);
316 if (model)
317 free(model);
318 return false;
319 }
320
321 dt_entry_array = (struct dt_entry*) malloc(sizeof(struct dt_entry) * num_entries);
322 ASSERT(dt_entry_array);
323
324 /* If we have '<X>; <Y>; <Z>' as platform data & '<A>; <B>; <C>' as board data.
325 * Then dt entry should look like
326 * <X ,A >;<X, B>;<X, C>;
327 * <Y ,A >;<Y, B>;<Y, C>;
328 * <Z ,A >;<Z, B>;<Z, C>;
329 */
330 i = 0;
331 k = 0;
332 n = 0;
333 for (i = 0; i < msm_data_count; i++) {
334 for (j = 0; j < board_data_count; j++) {
335 if (dtb_ver == DEV_TREE_VERSION_V3 && pmic_prop) {
336 for (n = 0; n < pmic_data_count; n++) {
337 dt_entry_array[k].platform_id = platform_data[i].platform_id;
338 dt_entry_array[k].soc_rev = platform_data[i].soc_rev;
339 dt_entry_array[k].variant_id = board_data[j].variant_id;
340 dt_entry_array[k].board_hw_subtype = board_data[j].platform_subtype;
341 dt_entry_array[k].pmic_rev[0]= pmic_data[n].pmic_version[0];
342 dt_entry_array[k].pmic_rev[1]= pmic_data[n].pmic_version[1];
343 dt_entry_array[k].pmic_rev[2]= pmic_data[n].pmic_version[2];
344 dt_entry_array[k].pmic_rev[3]= pmic_data[n].pmic_version[3];
345 dt_entry_array[k].offset = (uint32_t)dtb;
346 dt_entry_array[k].size = dtb_size;
347 k++;
348 }
349
350 } else {
351 dt_entry_array[k].platform_id = platform_data[i].platform_id;
352 dt_entry_array[k].soc_rev = platform_data[i].soc_rev;
353 dt_entry_array[k].variant_id = board_data[j].variant_id;
354 dt_entry_array[k].board_hw_subtype = board_data[j].platform_subtype;
355 dt_entry_array[k].pmic_rev[0]= board_pmic_target(0);
356 dt_entry_array[k].pmic_rev[1]= board_pmic_target(1);
357 dt_entry_array[k].pmic_rev[2]= board_pmic_target(2);
358 dt_entry_array[k].pmic_rev[3]= board_pmic_target(3);
359 dt_entry_array[k].offset = (uint32_t)dtb;
360 dt_entry_array[k].size = dtb_size;
vijay kumar89d36d82014-06-30 19:32:18 +0530361 k++;
362 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700363 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800364 }
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700365
Lijuan Gao9f152862014-08-18 13:45:24 +0800366 for (i=0 ;i < num_entries; i++) {
367 dprintf(SPEW, "Found an appended flattened device tree (%s - %u %u %u 0x%x)\n",
368 *model ? model : "unknown",
369 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 +0530370
Lijuan Gao9f152862014-08-18 13:45:24 +0800371 if (platform_dt_absolute_match(&(dt_entry_array[i]), dtb_list)) {
372 dprintf(SPEW, "Device tree exact match the board: <%u %u %u 0x%x> == <%u %u %u 0x%x>\n",
373 dt_entry_array[i].platform_id,
374 dt_entry_array[i].variant_id,
375 dt_entry_array[i].soc_rev,
376 dt_entry_array[i].board_hw_subtype,
377 board_platform_id(),
378 board_hardware_id(),
379 board_hardware_subtype(),
380 board_soc_version());
vijay kumar89d36d82014-06-30 19:32:18 +0530381
Lijuan Gao9f152862014-08-18 13:45:24 +0800382 } else {
383 dprintf(SPEW, "Device tree's msm_id doesn't match the board: <%u %u %u 0x%x> != <%u %u %u 0x%x>\n",
384 dt_entry_array[i].platform_id,
385 dt_entry_array[i].variant_id,
386 dt_entry_array[i].soc_rev,
387 dt_entry_array[i].board_hw_subtype,
388 board_platform_id(),
389 board_hardware_id(),
390 board_hardware_subtype(),
391 board_soc_version());
Channagoud Kadabia4dbe332013-09-05 17:44:11 -0700392 }
393 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800394
395 free(board_data);
396 free(platform_data);
397 if (pmic_data)
398 free(pmic_data);
399 free(dt_entry_array);
Dima Zavinc46f8382013-05-03 12:23:06 -0700400 }
Lijuan Gao9f152862014-08-18 13:45:24 +0800401 if (model)
vijay kumar89d36d82014-06-30 19:32:18 +0530402 free(model);
Lijuan Gao9f152862014-08-18 13:45:24 +0800403 return true;
Dima Zavinc46f8382013-05-03 12:23:06 -0700404}
405
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800406/*
Dima Zavin77e41f32013-03-06 16:10:43 -0800407 * Will relocate the DTB to the tags addr if the device tree is found and return
408 * its address
409 *
410 * Arguments: kernel - Start address of the kernel loaded in RAM
411 * tags - Start address of the tags loaded in RAM
Channagoud Kadabi704cd562013-04-25 15:19:59 -0700412 * kernel_size - Size of the kernel in bytes
413 *
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800414 * Return Value: DTB address : If appended device tree is found
Dima Zavin77e41f32013-03-06 16:10:43 -0800415 * 'NULL' : Otherwise
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800416 */
Matthew Qinbb7923d2015-02-09 10:56:09 +0800417void *dev_tree_appended(void *kernel, uint32_t kernel_size, uint32_t dtb_offset, void *tags)
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800418{
Dima Zavinc46f8382013-05-03 12:23:06 -0700419 void *kernel_end = kernel + kernel_size;
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800420 uint32_t app_dtb_offset = 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800421 void *dtb = NULL;
Shashank Mittalc0f10282013-07-15 14:53:31 -0700422 void *bestmatch_tag = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800423 struct dt_entry *best_match_dt_entry = NULL;
Shashank Mittalc0f10282013-07-15 14:53:31 -0700424 uint32_t bestmatch_tag_size;
Lijuan Gao9f152862014-08-18 13:45:24 +0800425 struct dt_entry_node *dt_entry_queue = NULL;
426 struct dt_entry_node *dt_node_tmp1 = NULL;
427 struct dt_entry_node *dt_node_tmp2 = NULL;
428
429
430 /* Initialize the dtb entry node*/
431 dt_entry_queue = (struct dt_entry_node *)
432 malloc(sizeof(struct dt_entry_node));
433
434 if (!dt_entry_queue) {
435 dprintf(CRITICAL, "Out of memory\n");
436 return NULL;
437 }
438 list_initialize(&dt_entry_queue->node);
439
Matthew Qinbb7923d2015-02-09 10:56:09 +0800440 if (dtb_offset)
441 app_dtb_offset = dtb_offset;
442 else
443 memcpy((void*) &app_dtb_offset, (void*) (kernel + DTB_OFFSET), sizeof(uint32_t));
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800444
vijay kumare2a5ea82014-06-25 12:24:14 +0530445 if (((uintptr_t)kernel + (uintptr_t)app_dtb_offset) < (uintptr_t)kernel) {
446 return NULL;
447 }
Dima Zavinc46f8382013-05-03 12:23:06 -0700448 dtb = kernel + app_dtb_offset;
vijay kumare2a5ea82014-06-25 12:24:14 +0530449 while (((uintptr_t)dtb + sizeof(struct fdt_header)) < (uintptr_t)kernel_end) {
Dima Zavinc46f8382013-05-03 12:23:06 -0700450 struct fdt_header dtb_hdr;
451 uint32_t dtb_size;
Dima Zavin77e41f32013-03-06 16:10:43 -0800452
Dima Zavinc46f8382013-05-03 12:23:06 -0700453 /* the DTB could be unaligned, so extract the header,
454 * and operate on it separately */
455 memcpy(&dtb_hdr, dtb, sizeof(struct fdt_header));
456 if (fdt_check_header((const void *)&dtb_hdr) != 0 ||
vijay kumare2a5ea82014-06-25 12:24:14 +0530457 ((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) < (uintptr_t)dtb) ||
458 ((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) > (uintptr_t)kernel_end))
Dima Zavinc46f8382013-05-03 12:23:06 -0700459 break;
460 dtb_size = fdt_totalsize(&dtb_hdr);
461
vijay kumar4f4405f2014-08-08 11:49:53 +0530462 if (check_aboot_addr_range_overlap((uint32_t)tags, dtb_size)) {
vijay kumarb05eed22014-06-24 16:30:18 +0530463 dprintf(CRITICAL, "Tags addresses overlap with aboot addresses.\n");
464 return NULL;
465 }
466
Lijuan Gao9f152862014-08-18 13:45:24 +0800467 dev_tree_compatible(dtb, dtb_size, dt_entry_queue);
Dima Zavinc46f8382013-05-03 12:23:06 -0700468
469 /* goto the next device tree if any */
470 dtb += dtb_size;
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800471 }
Dima Zavinc46f8382013-05-03 12:23:06 -0700472
Lijuan Gao9f152862014-08-18 13:45:24 +0800473 best_match_dt_entry = platform_dt_match_best(dt_entry_queue);
474 if (best_match_dt_entry){
475 bestmatch_tag = (void *)best_match_dt_entry->offset;
476 bestmatch_tag_size = best_match_dt_entry->size;
477 dprintf(INFO, "Best match DTB tags %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
478 best_match_dt_entry->platform_id, best_match_dt_entry->variant_id,
479 best_match_dt_entry->board_hw_subtype, best_match_dt_entry->soc_rev,
480 best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],
481 best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],
482 best_match_dt_entry->offset, best_match_dt_entry->size);
483 dprintf(INFO, "Using pmic info 0x%0x/0x%x/0x%x/0x%0x for device 0x%0x/0x%x/0x%x/0x%0x\n",
484 best_match_dt_entry->pmic_rev[0], best_match_dt_entry->pmic_rev[1],
485 best_match_dt_entry->pmic_rev[2], best_match_dt_entry->pmic_rev[3],
486 board_pmic_target(0), board_pmic_target(1),
487 board_pmic_target(2), board_pmic_target(3));
488 }
489 /* free queue's memory */
490 list_for_every_entry(&dt_entry_queue->node, dt_node_tmp1, dt_node, node) {
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -0800491 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +0800492 dt_entry_list_delete(dt_node_tmp1);
493 dt_node_tmp1 = dt_node_tmp2;
494 }
495
Shashank Mittalc0f10282013-07-15 14:53:31 -0700496 if(bestmatch_tag) {
Shashank Mittalc0f10282013-07-15 14:53:31 -0700497 memcpy(tags, bestmatch_tag, bestmatch_tag_size);
498 /* clear out the old DTB magic so kernel doesn't find it */
499 *((uint32_t *)(kernel + app_dtb_offset)) = 0;
500 return tags;
501 }
502
Dima Zavinc46f8382013-05-03 12:23:06 -0700503 dprintf(CRITICAL, "DTB offset is incorrect, kernel image does not have appended DTB\n");
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800504
David Ng59c4a782015-05-14 15:51:44 -0700505 dprintf(INFO, "Device info 0x%08x/%08x/0x%08x/%u, pmic 0x%0x/0x%x/0x%x/0x%0x\n",
506 board_platform_id(), board_soc_version(),
507 board_target_id(), board_hardware_subtype(),
508 board_pmic_target(0), board_pmic_target(1),
509 board_pmic_target(2), board_pmic_target(3));
Dima Zavin77e41f32013-03-06 16:10:43 -0800510 return NULL;
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800511}
512
Joel Kingaa335dc2013-06-03 16:11:08 -0700513/* Returns 0 if the device tree is valid. */
Deepa Dinamani87252952013-09-09 13:58:27 -0700514int dev_tree_validate(struct dt_table *table, unsigned int page_size, uint32_t *dt_hdr_size)
Joel Kingaa335dc2013-06-03 16:11:08 -0700515{
516 int dt_entry_size;
Channagoud Kadabid87c2772014-06-20 15:41:55 -0700517 uint64_t hdr_size;
Joel Kingaa335dc2013-06-03 16:11:08 -0700518
519 /* Validate the device tree table header */
520 if(table->magic != DEV_TREE_MAGIC) {
521 dprintf(CRITICAL, "ERROR: Bad magic in device tree table \n");
522 return -1;
523 }
524
525 if (table->version == DEV_TREE_VERSION_V1) {
526 dt_entry_size = sizeof(struct dt_entry_v1);
527 } else if (table->version == DEV_TREE_VERSION_V2) {
Lijuan Gao9f152862014-08-18 13:45:24 +0800528 dt_entry_size = sizeof(struct dt_entry_v2);
529 } else if (table->version == DEV_TREE_VERSION_V3) {
Joel Kingaa335dc2013-06-03 16:11:08 -0700530 dt_entry_size = sizeof(struct dt_entry);
531 } else {
532 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
533 table->version);
534 return -1;
535 }
536
Channagoud Kadabid87c2772014-06-20 15:41:55 -0700537 hdr_size = (uint64_t)table->num_entries * dt_entry_size + DEV_TREE_HEADER_SIZE;
538
Deepa Dinamani87252952013-09-09 13:58:27 -0700539 /* Roundup to page_size. */
540 hdr_size = ROUNDUP(hdr_size, page_size);
541
Channagoud Kadabid87c2772014-06-20 15:41:55 -0700542 if (hdr_size > UINT_MAX)
543 return -1;
544 else
545 *dt_hdr_size = hdr_size & UINT_MAX;
Joel Kingaa335dc2013-06-03 16:11:08 -0700546
547 return 0;
548}
549
Lijuan Gao9f152862014-08-18 13:45:24 +0800550static int platform_dt_absolute_match(struct dt_entry *cur_dt_entry, struct dt_entry_node *dt_list)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700551{
Lijuan Gaof8e95722014-12-23 03:03:12 -0500552 uint32_t cur_dt_hlos_ddr;
Lijuan Gao9f152862014-08-18 13:45:24 +0800553 uint32_t cur_dt_hw_platform;
554 uint32_t cur_dt_hw_subtype;
555 uint32_t cur_dt_msm_id;
556 dt_node *dt_node_tmp = NULL;
Channagoud Kadabi571193a2014-02-05 13:58:49 -0800557
Lijuan Gao9f152862014-08-18 13:45:24 +0800558 /* Platform-id
559 * bit no |31 24|23 16|15 0|
560 * |reserved|foundry-id|msm-id|
561 */
562 cur_dt_msm_id = (cur_dt_entry->platform_id & 0x0000ffff);
563 cur_dt_hw_platform = (cur_dt_entry->variant_id & 0x000000ff);
Lijuan Gao0621b862014-09-02 10:02:52 +0800564 cur_dt_hw_subtype = (cur_dt_entry->board_hw_subtype & 0xff);
Lijuan Gao9f152862014-08-18 13:45:24 +0800565
Lijuan Gaof8e95722014-12-23 03:03:12 -0500566 /* Determine the bits 10:8 to check the DT with the DDR Size */
567 cur_dt_hlos_ddr = (cur_dt_entry->board_hw_subtype & 0x700);
Channagoud Kadabi571193a2014-02-05 13:58:49 -0800568
Lijuan Gao9f152862014-08-18 13:45:24 +0800569 /* 1. must match the msm_id, platform_hw_id, platform_subtype and DDR size
570 * soc, board major/minor, pmic major/minor must less than board info
571 * 2. find the matched DTB then return 1
572 * 3. otherwise return 0
Maria Yu2e2d2c22013-07-03 19:20:33 +0800573 */
Lijuan Gao9f152862014-08-18 13:45:24 +0800574 if((cur_dt_msm_id == (board_platform_id() & 0x0000ffff)) &&
575 (cur_dt_hw_platform == board_hardware_id()) &&
576 (cur_dt_hw_subtype == board_hardware_subtype()) &&
Lijuan Gaof8e95722014-12-23 03:03:12 -0500577 (cur_dt_hlos_ddr == (target_get_hlos_subtype() & 0x700)) &&
Lijuan Gao9f152862014-08-18 13:45:24 +0800578 (cur_dt_entry->soc_rev <= board_soc_version()) &&
579 ((cur_dt_entry->variant_id & 0x00ffff00) <= (board_target_id() & 0x00ffff00)) &&
580 ((cur_dt_entry->pmic_rev[0] & 0x00ffff00) <= (board_pmic_target(0) & 0x00ffff00)) &&
581 ((cur_dt_entry->pmic_rev[1] & 0x00ffff00) <= (board_pmic_target(1) & 0x00ffff00)) &&
582 ((cur_dt_entry->pmic_rev[2] & 0x00ffff00) <= (board_pmic_target(2) & 0x00ffff00)) &&
583 ((cur_dt_entry->pmic_rev[3] & 0x00ffff00) <= (board_pmic_target(3) & 0x00ffff00))) {
Maria Yu2e2d2c22013-07-03 19:20:33 +0800584
Lijuan Gao9f152862014-08-18 13:45:24 +0800585 dt_node_tmp = dt_entry_list_init();
586 memcpy((char*)dt_node_tmp->dt_entry_m,(char*)cur_dt_entry, sizeof(struct dt_entry));
587
588 dprintf(SPEW, "Add DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
589 dt_node_tmp->dt_entry_m->platform_id, dt_node_tmp->dt_entry_m->variant_id,
590 dt_node_tmp->dt_entry_m->board_hw_subtype, dt_node_tmp->dt_entry_m->soc_rev,
591 dt_node_tmp->dt_entry_m->pmic_rev[0], dt_node_tmp->dt_entry_m->pmic_rev[1],
592 dt_node_tmp->dt_entry_m->pmic_rev[2], dt_node_tmp->dt_entry_m->pmic_rev[3],
593 dt_node_tmp->dt_entry_m->offset, dt_node_tmp->dt_entry_m->size);
594
595 insert_dt_entry_in_queue(dt_list, dt_node_tmp);
596 return 1;
597 }
598 return 0;
599}
600
601static int platform_dt_absolute_compat_match(struct dt_entry_node *dt_list, uint32_t dtb_info) {
602 struct dt_entry_node *dt_node_tmp1 = NULL;
603 struct dt_entry_node *dt_node_tmp2 = NULL;
604 uint32_t current_info = 0;
605 uint32_t board_info = 0;
606 uint32_t best_info = 0;
607 uint32_t current_pmic_model[4] = {0, 0, 0, 0};
608 uint32_t board_pmic_model[4] = {0, 0, 0, 0};
609 uint32_t best_pmic_model[4] = {0, 0, 0, 0};
610 uint32_t delete_current_dt = 0;
611 uint32_t i;
612
613 /* start to select the exact entry
614 * default to exact match 0, if find current DTB entry info is the same as board info,
615 * then exact match board info.
616 */
617 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
618 if (!dt_node_tmp1){
619 dprintf(SPEW, "Current node is the end\n");
620 break;
621 }
622 switch(dtb_info) {
623 case DTB_FOUNDRY:
624 current_info = ((dt_node_tmp1->dt_entry_m->platform_id) & 0x00ff0000);
Channagoud Kadabi4cffc272014-10-29 11:23:26 -0700625 board_info = board_foundry_id() << 16;
Lijuan Gao9f152862014-08-18 13:45:24 +0800626 break;
627 case DTB_PMIC_MODEL:
628 for (i = 0; i < 4; i++) {
629 current_pmic_model[i] = (dt_node_tmp1->dt_entry_m->pmic_rev[i] & 0xff);
630 board_pmic_model[i] = (board_pmic_target(i) & 0xff);
631 }
632 break;
Lijuan Gaof8e95722014-12-23 03:03:12 -0500633 case DTB_PANEL_TYPE:
634 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0x1800);
635 board_info = (target_get_hlos_subtype() & 0x1800);
636 break;
637 case DTB_BOOT_DEVICE:
638 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0xf0000);
639 board_info = (target_get_hlos_subtype() & 0xf0000);
640 break;
Lijuan Gao9f152862014-08-18 13:45:24 +0800641 default:
642 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
643 dtb_info);
Maria Yuca51ee22013-06-27 21:45:24 +0800644 return 0;
Lijuan Gao9f152862014-08-18 13:45:24 +0800645 }
646
647 if (dtb_info == DTB_PMIC_MODEL) {
648 if ((current_pmic_model[0] == board_pmic_model[0]) &&
649 (current_pmic_model[1] == board_pmic_model[1]) &&
650 (current_pmic_model[2] == board_pmic_model[2]) &&
651 (current_pmic_model[3] == board_pmic_model[3])) {
652
653 for (i = 0; i < 4; i++) {
654 best_pmic_model[i] = current_pmic_model[i];
655 }
656 break;
657 }
658 } else {
659 if (current_info == board_info) {
660 best_info = current_info;
661 break;
662 }
663 }
664 }
665
666 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
667 if (!dt_node_tmp1){
668 dprintf(SPEW, "Current node is the end\n");
669 break;
670 }
671 switch(dtb_info) {
672 case DTB_FOUNDRY:
673 current_info = ((dt_node_tmp1->dt_entry_m->platform_id) & 0x00ff0000);
674 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 }
679 break;
Lijuan Gaof8e95722014-12-23 03:03:12 -0500680 case DTB_PANEL_TYPE:
681 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0x1800);
682 break;
683 case DTB_BOOT_DEVICE:
684 current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0xf0000);
685 break;
Lijuan Gao9f152862014-08-18 13:45:24 +0800686 default:
687 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
688 dtb_info);
689 return 0;
690 }
691
692 if (dtb_info == DTB_PMIC_MODEL) {
693 if ((current_pmic_model[0] != best_pmic_model[0]) ||
694 (current_pmic_model[1] != best_pmic_model[1]) ||
695 (current_pmic_model[2] != best_pmic_model[2]) ||
696 (current_pmic_model[3] != best_pmic_model[3])) {
697
698 delete_current_dt = 1;
699 }
700 } else {
701 if (current_info != best_info) {
702 delete_current_dt = 1;
703 }
704 }
705
706 if (delete_current_dt) {
707 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
708 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
709 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
710 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
711 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
712 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
713
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -0800714 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +0800715 dt_entry_list_delete(dt_node_tmp1);
716 dt_node_tmp1 = dt_node_tmp2;
717 delete_current_dt = 0;
Maria Yuca51ee22013-06-27 21:45:24 +0800718 }
719 }
Maria Yuca51ee22013-06-27 21:45:24 +0800720
Maria Yu2e2d2c22013-07-03 19:20:33 +0800721 return 1;
Maria Yuca51ee22013-06-27 21:45:24 +0800722}
723
Lijuan Gao9f152862014-08-18 13:45:24 +0800724static int update_dtb_entry_node(struct dt_entry_node *dt_list, uint32_t dtb_info) {
725 struct dt_entry_node *dt_node_tmp1 = NULL;
726 struct dt_entry_node *dt_node_tmp2 = NULL;
727 uint32_t current_info = 0;
728 uint32_t board_info = 0;
729 uint32_t best_info = 0;
730
731 /* start to select the best entry*/
732 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
733 if (!dt_node_tmp1){
734 dprintf(SPEW, "Current node is the end\n");
735 break;
736 }
737 switch(dtb_info) {
738 case DTB_SOC:
739 current_info = dt_node_tmp1->dt_entry_m->soc_rev;
740 board_info = board_soc_version();
741 break;
742 case DTB_MAJOR_MINOR:
743 current_info = ((dt_node_tmp1->dt_entry_m->variant_id) & 0x00ffff00);
744 board_info = (board_target_id() & 0x00ffff00);
745 break;
746 case DTB_PMIC0:
747 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[0]) & 0x00ffff00);
748 board_info = (board_pmic_target(0) & 0x00ffff00);
749 break;
750 case DTB_PMIC1:
751 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[1]) & 0x00ffff00);
752 board_info = (board_pmic_target(1) & 0x00ffff00);
753 break;
754 case DTB_PMIC2:
755 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[2]) & 0x00ffff00);
756 board_info = (board_pmic_target(2) & 0x00ffff00);
757 break;
758 case DTB_PMIC3:
759 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[3]) & 0x00ffff00);
760 board_info = (board_pmic_target(3) & 0x00ffff00);
761 break;
762 default:
763 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
764 dtb_info);
765 return 0;
766 }
767
768 if (current_info == board_info) {
769 best_info = current_info;
770 break;
771 }
772 if ((current_info < board_info) && (current_info > best_info)) {
773 best_info = current_info;
774 }
775 if (current_info < best_info) {
776 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
777 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
778 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
779 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
780 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
781 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
782
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -0800783 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +0800784 dt_entry_list_delete(dt_node_tmp1);
785 dt_node_tmp1 = dt_node_tmp2;
786 }
787 }
788
789 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
790 if (!dt_node_tmp1){
791 dprintf(SPEW, "Current node is the end\n");
792 break;
793 }
794 switch(dtb_info) {
795 case DTB_SOC:
796 current_info = dt_node_tmp1->dt_entry_m->soc_rev;
797 break;
798 case DTB_MAJOR_MINOR:
799 current_info = ((dt_node_tmp1->dt_entry_m->variant_id) & 0x00ffff00);
800 break;
801 case DTB_PMIC0:
802 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[0]) & 0x00ffff00);
803 break;
804 case DTB_PMIC1:
805 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[1]) & 0x00ffff00);
806 break;
807 case DTB_PMIC2:
808 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[2]) & 0x00ffff00);
809 break;
810 case DTB_PMIC3:
811 current_info = ((dt_node_tmp1->dt_entry_m->pmic_rev[3]) & 0x00ffff00);
812 break;
813 default:
814 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in dt node check \n",
815 dtb_info);
816 return 0;
817 }
818
819 if (current_info != best_info) {
820 dprintf(SPEW, "Delete don't fit DTB entry %u/%08x/0x%08x/%x/%x/%x/%x/%x/%x/%x\n",
821 dt_node_tmp1->dt_entry_m->platform_id, dt_node_tmp1->dt_entry_m->variant_id,
822 dt_node_tmp1->dt_entry_m->board_hw_subtype, dt_node_tmp1->dt_entry_m->soc_rev,
823 dt_node_tmp1->dt_entry_m->pmic_rev[0], dt_node_tmp1->dt_entry_m->pmic_rev[1],
824 dt_node_tmp1->dt_entry_m->pmic_rev[2], dt_node_tmp1->dt_entry_m->pmic_rev[3],
825 dt_node_tmp1->dt_entry_m->offset, dt_node_tmp1->dt_entry_m->size);
826
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -0800827 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +0800828 dt_entry_list_delete(dt_node_tmp1);
829 dt_node_tmp1 = dt_node_tmp2;
830 }
831 }
832 return 1;
833}
834
835static struct dt_entry *platform_dt_match_best(struct dt_entry_node *dt_list)
836{
837 struct dt_entry_node *dt_node_tmp1 = NULL;
838
839 /* check Foundry id
840 * the foundry id must exact match board founddry id, this is compatibility check,
841 * if couldn't find the exact match from DTB, will exact match 0x0.
842 */
843 if (!platform_dt_absolute_compat_match(dt_list, DTB_FOUNDRY))
844 return NULL;
845
846 /* check PMIC model
847 * the PMIC model must exact match board PMIC model, this is compatibility check,
848 * if couldn't find the exact match from DTB, will exact match 0x0.
849 */
850 if (!platform_dt_absolute_compat_match(dt_list, DTB_PMIC_MODEL))
851 return NULL;
852
Lijuan Gaof8e95722014-12-23 03:03:12 -0500853 /* check panel type
854 * the panel type must exact match board panel type, this is compatibility check,
855 * if couldn't find the exact match from DTB, will exact match 0x0.
856 */
857 if (!platform_dt_absolute_compat_match(dt_list, DTB_PANEL_TYPE))
858 return NULL;
859
860 /* check boot device subtype
861 * the boot device subtype must exact match board boot device subtype, this is compatibility check,
862 * if couldn't find the exact match from DTB, will exact match 0x0.
863 */
864 if (!platform_dt_absolute_compat_match(dt_list, DTB_BOOT_DEVICE))
865 return NULL;
866
Lijuan Gao9f152862014-08-18 13:45:24 +0800867 /* check soc version
868 * the suitable soc version must less than or equal to board soc version
869 */
870 if (!update_dtb_entry_node(dt_list, DTB_SOC))
871 return NULL;
872
873 /*check major and minor version
874 * the suitable major&minor version must less than or equal to board major&minor version
875 */
876 if (!update_dtb_entry_node(dt_list, DTB_MAJOR_MINOR))
877 return NULL;
878
879 /*check pmic info
880 * the suitable pmic major&minor info must less than or equal to board pmic major&minor version
881 */
882 if (!update_dtb_entry_node(dt_list, DTB_PMIC0))
883 return NULL;
884 if (!update_dtb_entry_node(dt_list, DTB_PMIC1))
885 return NULL;
886 if (!update_dtb_entry_node(dt_list, DTB_PMIC2))
887 return NULL;
888 if (!update_dtb_entry_node(dt_list, DTB_PMIC3))
889 return NULL;
890
891 list_for_every_entry(&dt_list->node, dt_node_tmp1, dt_node, node) {
892 if (!dt_node_tmp1) {
893 dprintf(CRITICAL, "ERROR: Couldn't find the suitable DTB!\n");
894 return NULL;
895 }
896 if (dt_node_tmp1->dt_entry_m)
897 return dt_node_tmp1->dt_entry_m;
898 }
899
900 return NULL;
901}
902
903/* Function to obtain the index information for the correct device tree
904 * based on the platform data.
905 * If a matching device tree is found, the information is returned in the
906 * "dt_entry_info" out parameter and a function value of 0 is returned, otherwise
907 * a non-zero function value is returned.
908 */
909int dev_tree_get_entry_info(struct dt_table *table, struct dt_entry *dt_entry_info)
Maria Yuca51ee22013-06-27 21:45:24 +0800910{
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700911 uint32_t i;
Lijuan Gao9f152862014-08-18 13:45:24 +0800912 unsigned char *table_ptr = NULL;
Joel Kingaa335dc2013-06-03 16:11:08 -0700913 struct dt_entry dt_entry_buf_1;
Lijuan Gao9f152862014-08-18 13:45:24 +0800914 struct dt_entry *cur_dt_entry = NULL;
915 struct dt_entry *best_match_dt_entry = NULL;
916 struct dt_entry_v1 *dt_entry_v1 = NULL;
917 struct dt_entry_v2 *dt_entry_v2 = NULL;
918 struct dt_entry_node *dt_entry_queue = NULL;
919 struct dt_entry_node *dt_node_tmp1 = NULL;
920 struct dt_entry_node *dt_node_tmp2 = NULL;
Maria Yu2e2d2c22013-07-03 19:20:33 +0800921 uint32_t found = 0;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700922
Joel Kingaa335dc2013-06-03 16:11:08 -0700923 if (!dt_entry_info) {
924 dprintf(CRITICAL, "ERROR: Bad parameter passed to %s \n",
925 __func__);
926 return -1;
927 }
928
929 table_ptr = (unsigned char *)table + DEV_TREE_HEADER_SIZE;
930 cur_dt_entry = &dt_entry_buf_1;
931 best_match_dt_entry = NULL;
Lijuan Gao9f152862014-08-18 13:45:24 +0800932 dt_entry_queue = (struct dt_entry_node *)
933 malloc(sizeof(struct dt_entry_node));
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700934
Lijuan Gao9f152862014-08-18 13:45:24 +0800935 if (!dt_entry_queue) {
936 dprintf(CRITICAL, "Out of memory\n");
937 return -1;
938 }
939
940 list_initialize(&dt_entry_queue->node);
941 dprintf(INFO, "DTB Total entry: %d, DTB version: %d\n", table->num_entries, table->version);
Maria Yu2e2d2c22013-07-03 19:20:33 +0800942 for(i = 0; found == 0 && i < table->num_entries; i++)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700943 {
Joel Kingaa335dc2013-06-03 16:11:08 -0700944 memset(cur_dt_entry, 0, sizeof(struct dt_entry));
945 switch(table->version) {
946 case DEV_TREE_VERSION_V1:
947 dt_entry_v1 = (struct dt_entry_v1 *)table_ptr;
948 cur_dt_entry->platform_id = dt_entry_v1->platform_id;
949 cur_dt_entry->variant_id = dt_entry_v1->variant_id;
950 cur_dt_entry->soc_rev = dt_entry_v1->soc_rev;
Lijuan Gao9f152862014-08-18 13:45:24 +0800951 cur_dt_entry->board_hw_subtype = (dt_entry_v1->variant_id >> 0x18);
952 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
953 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
954 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
955 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
Joel Kingaa335dc2013-06-03 16:11:08 -0700956 cur_dt_entry->offset = dt_entry_v1->offset;
957 cur_dt_entry->size = dt_entry_v1->size;
958 table_ptr += sizeof(struct dt_entry_v1);
959 break;
960 case DEV_TREE_VERSION_V2:
Lijuan Gao9f152862014-08-18 13:45:24 +0800961 dt_entry_v2 = (struct dt_entry_v2*)table_ptr;
962 cur_dt_entry->platform_id = dt_entry_v2->platform_id;
963 cur_dt_entry->variant_id = dt_entry_v2->variant_id;
964 cur_dt_entry->soc_rev = dt_entry_v2->soc_rev;
965 /* For V2 version of DTBs we have platform version field as part
966 * of variant ID, in such case the subtype will be mentioned as 0x0
967 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
968 * SS -- Subtype
969 * PM -- Platform major version
970 * Pm -- Platform minor version
971 * PH -- Platform hardware CDP/MTP
972 * In such case to make it compatible with LK algorithm move the subtype
973 * from variant_id to subtype field
974 */
975 if (dt_entry_v2->board_hw_subtype == 0)
976 cur_dt_entry->board_hw_subtype = (cur_dt_entry->variant_id >> 0x18);
977 else
978 cur_dt_entry->board_hw_subtype = dt_entry_v2->board_hw_subtype;
979 cur_dt_entry->pmic_rev[0] = board_pmic_target(0);
980 cur_dt_entry->pmic_rev[1] = board_pmic_target(1);
981 cur_dt_entry->pmic_rev[2] = board_pmic_target(2);
982 cur_dt_entry->pmic_rev[3] = board_pmic_target(3);
983 cur_dt_entry->offset = dt_entry_v2->offset;
984 cur_dt_entry->size = dt_entry_v2->size;
985 table_ptr += sizeof(struct dt_entry_v2);
986 break;
987 case DEV_TREE_VERSION_V3:
Joel Kingaa335dc2013-06-03 16:11:08 -0700988 memcpy(cur_dt_entry, (struct dt_entry *)table_ptr,
989 sizeof(struct dt_entry));
Lijuan Gao9f152862014-08-18 13:45:24 +0800990 /* For V3 version of DTBs we have platform version field as part
991 * of variant ID, in such case the subtype will be mentioned as 0x0
992 * As the qcom, board-id = <0xSSPMPmPH, 0x0>
993 * SS -- Subtype
994 * PM -- Platform major version
995 * Pm -- Platform minor version
996 * PH -- Platform hardware CDP/MTP
997 * In such case to make it compatible with LK algorithm move the subtype
998 * from variant_id to subtype field
999 */
1000 if (cur_dt_entry->board_hw_subtype == 0)
1001 cur_dt_entry->board_hw_subtype = (cur_dt_entry->variant_id >> 0x18);
1002
Joel Kingaa335dc2013-06-03 16:11:08 -07001003 table_ptr += sizeof(struct dt_entry);
1004 break;
1005 default:
1006 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
1007 table->version);
Lijuan Gao9f152862014-08-18 13:45:24 +08001008 free(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001009 return -1;
1010 }
1011
Lijuan Gao9f152862014-08-18 13:45:24 +08001012 /* DTBs must match the platform_id, platform_hw_id, platform_subtype and DDR size.
1013 * The satisfactory DTBs are stored in dt_entry_queue
1014 */
1015 platform_dt_absolute_match(cur_dt_entry, dt_entry_queue);
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -08001016
Lijuan Gao9f152862014-08-18 13:45:24 +08001017 }
1018 best_match_dt_entry = platform_dt_match_best(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001019 if (best_match_dt_entry) {
1020 *dt_entry_info = *best_match_dt_entry;
Maria Yu2e2d2c22013-07-03 19:20:33 +08001021 found = 1;
1022 }
1023
1024 if (found != 0) {
Sundarajan Srinivasan763c0db2014-05-20 17:08:36 -07001025 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 -07001026 dt_entry_info->platform_id, dt_entry_info->soc_rev,
1027 dt_entry_info->variant_id, dt_entry_info->board_hw_subtype,
Lijuan Gao9f152862014-08-18 13:45:24 +08001028 board_platform_id(), board_soc_version(),
1029 board_target_id(), board_hardware_subtype());
1030 if (dt_entry_info->pmic_rev[0] == 0 && dt_entry_info->pmic_rev[0] == 0 &&
1031 dt_entry_info->pmic_rev[0] == 0 && dt_entry_info->pmic_rev[0] == 0) {
1032 dprintf(SPEW, "No maintain pmic info in DTB, device pmic info is 0x%0x/0x%x/0x%x/0x%0x\n",
1033 board_pmic_target(0), board_pmic_target(1),
1034 board_pmic_target(2), board_pmic_target(3));
1035 } else {
1036 dprintf(INFO, "Using pmic info 0x%0x/0x%x/0x%x/0x%0x for device 0x%0x/0x%x/0x%x/0x%0x\n",
1037 dt_entry_info->pmic_rev[0], dt_entry_info->pmic_rev[1],
1038 dt_entry_info->pmic_rev[2], dt_entry_info->pmic_rev[3],
1039 board_pmic_target(0), board_pmic_target(1),
1040 board_pmic_target(2), board_pmic_target(3));
1041 }
Joel Kingaa335dc2013-06-03 16:11:08 -07001042 return 0;
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -08001043 }
1044
Lijuan Gao9f152862014-08-18 13:45:24 +08001045 dprintf(CRITICAL, "ERROR: Unable to find suitable device tree for device (%u/0x%08x/0x%08x/%u)\n",
1046 board_platform_id(), board_soc_version(),
1047 board_target_id(), board_hardware_subtype());
1048
1049 list_for_every_entry(&dt_entry_queue->node, dt_node_tmp1, dt_node, node) {
1050 /* free node memory */
Veera Sundaram Sankaran00181512014-12-09 11:23:39 -08001051 dt_node_tmp2 = (struct dt_entry_node *) dt_node_tmp1->node.prev;
Lijuan Gao9f152862014-08-18 13:45:24 +08001052 dt_entry_list_delete(dt_node_tmp1);
1053 dt_node_tmp1 = dt_node_tmp2;
1054 }
1055 free(dt_entry_queue);
Joel Kingaa335dc2013-06-03 16:11:08 -07001056 return -1;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001057}
1058
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001059/* Function to add the first RAM partition info to the device tree.
1060 * Note: The function replaces the reg property in the "/memory" node
1061 * with the addr and size provided.
1062 */
1063int dev_tree_add_first_mem_info(uint32_t *fdt, uint32_t offset, uint32_t addr, uint32_t size)
1064{
1065 int ret;
1066
1067 ret = fdt_setprop_u32(fdt, offset, "reg", addr);
1068
1069 if (ret)
1070 {
1071 dprintf(CRITICAL, "Failed to add the memory information addr: %d\n",
1072 ret);
1073 }
1074
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001075 ret = fdt_appendprop_u32(fdt, offset, "reg", size);
1076
1077 if (ret)
1078 {
1079 dprintf(CRITICAL, "Failed to add the memory information size: %d\n",
1080 ret);
1081 }
1082
1083 return ret;
1084}
1085
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001086static 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 -07001087{
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001088 int len;
1089 uint32_t *valp;
1090 int ret;
1091 uint32_t offset;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001092
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001093 mem_node->offset = mem_node_offset;
1094
1095 /* Get offset of the root node */
1096 ret = fdt_path_offset(fdt, "/");
1097 if (ret < 0)
1098 {
1099 dprintf(CRITICAL, "Could not find memory node.\n");
1100 return ret;
1101 }
1102
1103 offset = ret;
1104
1105 /* Find the #address-cells size. */
1106 valp = (uint32_t*)fdt_getprop(fdt, offset, "#address-cells", &len);
Lijuan Gaoae0927b2014-07-18 17:16:16 +08001107 if (len <= 0 || !valp)
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001108 {
1109 if (len == -FDT_ERR_NOTFOUND)
1110 {
1111 /* Property not found.
1112 * Assume standard sizes.
1113 */
1114 mem_node->addr_cell_size = 2;
1115 dprintf(CRITICAL, "Using default #addr_cell_size: %u\n", mem_node->addr_cell_size);
1116 }
1117 else
1118 {
1119 dprintf(CRITICAL, "Error finding the #address-cells property\n");
1120 return len;
1121 }
1122 }
1123 else
1124 mem_node->addr_cell_size = fdt32_to_cpu(*valp);
1125
1126 /* Find the #size-cells size. */
1127 valp = (uint32_t*)fdt_getprop(fdt, offset, "#size-cells", &len);
Lijuan Gaoae0927b2014-07-18 17:16:16 +08001128 if (len <= 0 || !valp)
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001129 {
1130 if (len == -FDT_ERR_NOTFOUND)
1131 {
1132 /* Property not found.
1133 * Assume standard sizes.
1134 */
1135 mem_node->size_cell_size = 1;
1136 dprintf(CRITICAL, "Using default #size_cell_size: %u\n", mem_node->size_cell_size);
1137 }
1138 else
1139 {
1140 dprintf(CRITICAL, "Error finding the #size-cells property\n");
1141 return len;
1142 }
1143 }
1144 else
1145 mem_node->size_cell_size = fdt32_to_cpu(*valp);
1146
1147 return 0;
1148}
1149
1150static void dev_tree_update_memory_node(uint32_t offset)
1151{
1152 mem_node.offset = offset;
1153 mem_node.addr_cell_size = 1;
1154 mem_node.size_cell_size = 1;
1155}
1156
1157/* Function to add the subsequent RAM partition info to the device tree. */
1158int dev_tree_add_mem_info(void *fdt, uint32_t offset, uint64_t addr, uint64_t size)
1159{
1160 int ret = 0;
1161
1162 if(smem_get_ram_ptable_version() >= 1)
1163 {
1164 ret = dev_tree_query_memory_cell_sizes(fdt, &mem_node, offset);
1165 if (ret < 0)
1166 {
1167 dprintf(CRITICAL, "Could not find #address-cells and #size-cells properties: ret %d\n", ret);
1168 return ret;
1169 }
1170
1171 }
1172 else
1173 {
1174 dev_tree_update_memory_node(offset);
1175 }
1176
1177 if (!(mem_node.mem_info_cnt))
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001178 {
1179 /* Replace any other reg prop in the memory node. */
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001180
1181 /* cell_size is the number of 32 bit words used to represent an address/length in the device tree.
1182 * memory node in DT can be either 32-bit(cell-size = 1) or 64-bit(cell-size = 2).So when updating
1183 * the memory node in the device tree, we write one word or two words based on cell_size = 1 or 2.
1184 */
1185
1186 if(mem_node.addr_cell_size == 2)
1187 {
1188 ret = fdt_setprop_u32(fdt, mem_node.offset, "reg", addr >> 32);
1189 if(ret)
1190 {
1191 dprintf(CRITICAL, "ERROR: Could not set prop reg for memory node\n");
1192 return ret;
1193 }
1194
1195 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1196 if(ret)
1197 {
1198 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1199 return ret;
1200 }
1201 }
1202 else
1203 {
1204 ret = fdt_setprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1205 if(ret)
1206 {
1207 dprintf(CRITICAL, "ERROR: Could not set prop reg for memory node\n");
1208 return ret;
1209 }
1210 }
1211
1212 mem_node.mem_info_cnt = 1;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001213 }
1214 else
1215 {
1216 /* Append the mem info to the reg prop for subsequent nodes. */
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001217 if(mem_node.addr_cell_size == 2)
1218 {
1219 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", addr >> 32);
1220 if(ret)
1221 {
1222 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1223 return ret;
1224 }
1225 }
1226
1227 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)addr);
1228 if(ret)
1229 {
1230 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1231 return ret;
1232 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001233 }
1234
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001235 if(mem_node.size_cell_size == 2)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001236 {
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001237 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", size>>32);
1238 if(ret)
1239 {
1240 dprintf(CRITICAL, "ERROR: Could not append prop reg for memory node\n");
1241 return ret;
1242 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001243 }
1244
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001245 ret = fdt_appendprop_u32(fdt, mem_node.offset, "reg", (uint32_t)size);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001246
1247 if (ret)
1248 {
1249 dprintf(CRITICAL, "Failed to add the memory information size: %d\n",
1250 ret);
Sundarajan Srinivasan44de4342013-07-08 14:47:13 -07001251 return ret;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001252 }
1253
1254 return ret;
1255}
1256
1257/* Top level function that updates the device tree. */
1258int update_device_tree(void *fdt, const char *cmdline,
1259 void *ramdisk, uint32_t ramdisk_size)
1260{
1261 int ret = 0;
1262 uint32_t offset;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001263
1264 /* Check the device tree header */
1265 ret = fdt_check_header(fdt);
1266 if (ret)
1267 {
1268 dprintf(CRITICAL, "Invalid device tree header \n");
1269 return ret;
1270 }
1271
Deepa Dinamani1c970732013-04-19 14:23:01 -07001272 /* Add padding to make space for new nodes and properties. */
1273 ret = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + DTB_PAD_SIZE);
1274 if (ret!= 0)
1275 {
1276 dprintf(CRITICAL, "Failed to move/resize dtb buffer: %d\n", ret);
1277 return ret;
1278 }
1279
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001280 /* Get offset of the memory node */
1281 ret = fdt_path_offset(fdt, "/memory");
1282 if (ret < 0)
1283 {
1284 dprintf(CRITICAL, "Could not find memory node.\n");
1285 return ret;
1286 }
1287
1288 offset = ret;
1289
1290 ret = target_dev_tree_mem(fdt, offset);
1291 if(ret)
1292 {
1293 dprintf(CRITICAL, "ERROR: Cannot update memory node\n");
1294 return ret;
1295 }
1296
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001297 /* Get offset of the chosen node */
1298 ret = fdt_path_offset(fdt, "/chosen");
1299 if (ret < 0)
1300 {
1301 dprintf(CRITICAL, "Could not find chosen node.\n");
1302 return ret;
1303 }
1304
1305 offset = ret;
Maria Yuabde9542014-07-07 14:49:34 +08001306 if (cmdline)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001307 {
Maria Yuabde9542014-07-07 14:49:34 +08001308 /* Adding the cmdline to the chosen node */
1309 ret = fdt_appendprop_string(fdt, offset, (const char*)"bootargs", (const void*)cmdline);
1310 if (ret)
1311 {
1312 dprintf(CRITICAL, "ERROR: Cannot update chosen node [bootargs]\n");
1313 return ret;
1314 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001315 }
1316
Joonwoo Parka5b5f492014-02-13 18:24:48 -08001317 if (ramdisk_size) {
1318 /* Adding the initrd-start to the chosen node */
1319 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-start",
1320 (uint32_t)ramdisk);
1321 if (ret)
1322 {
1323 dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-start]\n");
1324 return ret;
1325 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001326
Joonwoo Parka5b5f492014-02-13 18:24:48 -08001327 /* Adding the initrd-end to the chosen node */
1328 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-end",
1329 ((uint32_t)ramdisk + ramdisk_size));
1330 if (ret)
1331 {
1332 dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-end]\n");
1333 return ret;
1334 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001335 }
1336
1337 fdt_pack(fdt);
1338
Channagoud Kadabiffaea422014-12-05 15:45:41 -08001339#if ENABLE_PARTIAL_GOODS_SUPPORT
1340 update_partial_goods_dtb_nodes(fdt);
1341#endif
1342
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -07001343 return ret;
1344}
Maria Yuca51ee22013-06-27 21:45:24 +08001345