blob: e940f9c108492f4c8bee86dbef3d0cf1bc32ba7b [file] [log] [blame]
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -08001/* Copyright (c) 2012-2013, 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>
38
Joel Kingaa335dc2013-06-03 16:11:08 -070039struct dt_entry_v1
40{
41 uint32_t platform_id;
42 uint32_t variant_id;
43 uint32_t soc_rev;
44 uint32_t offset;
45 uint32_t size;
46};
47
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -070048extern int target_is_emmc_boot(void);
49extern uint32_t target_dev_tree_mem(void *fdt, uint32_t memory_node_offset);
Deepa Dinamanic55f01b2013-05-30 14:05:56 -070050/* TODO: This function needs to be moved to target layer to check violations
51 * against all the other regions as well.
52 */
53extern int check_aboot_addr_range_overlap(uint32_t start, uint32_t size);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -070054
Dima Zavinc46f8382013-05-03 12:23:06 -070055struct msm_id
56{
57 uint32_t platform_id;
58 uint32_t hardware_id;
59 uint32_t soc_rev;
60};
61
Shashank Mittalc0f10282013-07-15 14:53:31 -070062/* Returns soc version if platform id and hardware id matches
63 otherwise return 0xFFFFFFFF */
64#define INVALID_SOC_REV_ID 0XFFFFFFFF
65static uint32_t dev_tree_compatible(void *dtb)
Dima Zavinc46f8382013-05-03 12:23:06 -070066{
67 int root_offset;
68 const void *prop;
69 char model[128];
70 struct msm_id msm_id;
71 int len;
72
73 root_offset = fdt_path_offset(dtb, "/");
74 if (root_offset < 0)
75 return false;
76
77 prop = fdt_getprop(dtb, root_offset, "model", &len);
78 if (prop && len > 0) {
79 memcpy(model, prop, MIN((int)sizeof(model), len));
80 model[sizeof(model) - 1] = '\0';
81 } else {
82 model[0] = '\0';
83 }
84
85 prop = fdt_getprop(dtb, root_offset, "qcom,msm-id", &len);
86 if (!prop || len <= 0) {
87 dprintf(INFO, "qcom,msm-id entry not found\n");
88 return false;
89 } else if (len < (int)sizeof(struct msm_id)) {
90 dprintf(INFO, "qcom,msm-id entry size mismatch (%d != %d)\n",
91 len, sizeof(struct msm_id));
92 return false;
93 }
94 msm_id.platform_id = fdt32_to_cpu(((const struct msm_id *)prop)->platform_id);
95 msm_id.hardware_id = fdt32_to_cpu(((const struct msm_id *)prop)->hardware_id);
96 msm_id.soc_rev = fdt32_to_cpu(((const struct msm_id *)prop)->soc_rev);
97
98 dprintf(INFO, "Found an appended flattened device tree (%s - %d %d 0x%x)\n",
99 *model ? model : "unknown",
100 msm_id.platform_id, msm_id.hardware_id, msm_id.soc_rev);
101
102 if (msm_id.platform_id != board_platform_id() ||
Shashank Mittalc0f10282013-07-15 14:53:31 -0700103 msm_id.hardware_id != board_hardware_id()) {
Dima Zavinc46f8382013-05-03 12:23:06 -0700104 dprintf(INFO, "Device tree's msm_id doesn't match the board: <%d %d 0x%x> != <%d %d 0x%x>\n",
105 msm_id.platform_id,
106 msm_id.hardware_id,
107 msm_id.soc_rev,
108 board_platform_id(),
109 board_hardware_id(),
110 board_soc_version());
Shashank Mittalc0f10282013-07-15 14:53:31 -0700111 return INVALID_SOC_REV_ID;
Dima Zavinc46f8382013-05-03 12:23:06 -0700112 }
113
Channagoud Kadabie153f502013-08-02 11:56:38 -0700114 dprintf(INFO, "Device tree's msm_id matches the board: <%d %d 0x%x> == <%d %d 0x%x>\n",
Shashank Mittalc0f10282013-07-15 14:53:31 -0700115 msm_id.platform_id,
116 msm_id.hardware_id,
117 msm_id.soc_rev,
118 board_platform_id(),
119 board_hardware_id(),
120 board_soc_version());
121 return msm_id.soc_rev;
Dima Zavinc46f8382013-05-03 12:23:06 -0700122}
123
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800124/*
Dima Zavin77e41f32013-03-06 16:10:43 -0800125 * Will relocate the DTB to the tags addr if the device tree is found and return
126 * its address
127 *
128 * Arguments: kernel - Start address of the kernel loaded in RAM
129 * tags - Start address of the tags loaded in RAM
Channagoud Kadabi704cd562013-04-25 15:19:59 -0700130 * kernel_size - Size of the kernel in bytes
131 *
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800132 * Return Value: DTB address : If appended device tree is found
Dima Zavin77e41f32013-03-06 16:10:43 -0800133 * 'NULL' : Otherwise
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800134 */
Dima Zavinc46f8382013-05-03 12:23:06 -0700135void *dev_tree_appended(void *kernel, uint32_t kernel_size, void *tags)
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800136{
Dima Zavinc46f8382013-05-03 12:23:06 -0700137 void *kernel_end = kernel + kernel_size;
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800138 uint32_t app_dtb_offset = 0;
Dima Zavinc46f8382013-05-03 12:23:06 -0700139 void *dtb;
Shashank Mittalc0f10282013-07-15 14:53:31 -0700140 void *bestmatch_tag = NULL;
141 uint32_t bestmatch_tag_size;
142 uint32_t bestmatch_soc_rev_id = INVALID_SOC_REV_ID;
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800143
144 memcpy((void*) &app_dtb_offset, (void*) (kernel + DTB_OFFSET), sizeof(uint32_t));
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800145
vijay kumarb3898ea2014-06-25 12:24:14 +0530146 if (((uintptr_t)kernel + (uintptr_t)app_dtb_offset) < (uintptr_t)kernel) {
147 return NULL;
148 }
Dima Zavinc46f8382013-05-03 12:23:06 -0700149 dtb = kernel + app_dtb_offset;
vijay kumarb3898ea2014-06-25 12:24:14 +0530150 while (((uintptr_t)dtb + sizeof(struct fdt_header)) < (uintptr_t)kernel_end) {
Shashank Mittalc0f10282013-07-15 14:53:31 -0700151 uint32_t dtb_soc_rev_id;
Dima Zavinc46f8382013-05-03 12:23:06 -0700152 struct fdt_header dtb_hdr;
153 uint32_t dtb_size;
Dima Zavin77e41f32013-03-06 16:10:43 -0800154
Dima Zavinc46f8382013-05-03 12:23:06 -0700155 /* the DTB could be unaligned, so extract the header,
156 * and operate on it separately */
157 memcpy(&dtb_hdr, dtb, sizeof(struct fdt_header));
158 if (fdt_check_header((const void *)&dtb_hdr) != 0 ||
vijay kumarb3898ea2014-06-25 12:24:14 +0530159 ((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) < (uintptr_t)dtb) ||
160 ((uintptr_t)dtb + (uintptr_t)fdt_totalsize((const void *)&dtb_hdr) > (uintptr_t)kernel_end))
Dima Zavinc46f8382013-05-03 12:23:06 -0700161 break;
162 dtb_size = fdt_totalsize(&dtb_hdr);
163
vijay kumard3ba56f2014-06-24 16:30:18 +0530164 if (check_aboot_addr_range_overlap(tags, dtb_size)) {
165 dprintf(CRITICAL, "Tags addresses overlap with aboot addresses.\n");
166 return NULL;
167 }
168
Dima Zavinc46f8382013-05-03 12:23:06 -0700169 /* now that we know we have a valid DTB, we need to copy
170 * it somewhere aligned, like tags */
171 memcpy(tags, dtb, dtb_size);
172
Shashank Mittalc0f10282013-07-15 14:53:31 -0700173 dtb_soc_rev_id = dev_tree_compatible(tags);
174 if (dtb_soc_rev_id == board_soc_version()) {
Dima Zavinc46f8382013-05-03 12:23:06 -0700175 /* clear out the old DTB magic so kernel doesn't find it */
176 *((uint32_t *)(kernel + app_dtb_offset)) = 0;
177 return tags;
Shashank Mittalc0f10282013-07-15 14:53:31 -0700178 } else if ((dtb_soc_rev_id != INVALID_SOC_REV_ID) &&
179 (dtb_soc_rev_id < board_soc_version())) {
180 /* if current bestmatch is less than new dtb_soc_rev_id then update
181 bestmatch_tag */
182 if((bestmatch_soc_rev_id == INVALID_SOC_REV_ID) ||
183 (bestmatch_soc_rev_id < dtb_soc_rev_id)) {
184 bestmatch_tag = dtb;
185 bestmatch_tag_size = dtb_size;
186 bestmatch_soc_rev_id = dtb_soc_rev_id;
187 }
Dima Zavin77e41f32013-03-06 16:10:43 -0800188 }
Dima Zavinc46f8382013-05-03 12:23:06 -0700189
190 /* goto the next device tree if any */
191 dtb += dtb_size;
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800192 }
Dima Zavinc46f8382013-05-03 12:23:06 -0700193
Shashank Mittalc0f10282013-07-15 14:53:31 -0700194 if(bestmatch_tag) {
195 dprintf(INFO,"DTB found with bestmatch soc rev id 0x%x.Board soc rev id 0x%x\n",
196 bestmatch_soc_rev_id, board_soc_version());
197 memcpy(tags, bestmatch_tag, bestmatch_tag_size);
198 /* clear out the old DTB magic so kernel doesn't find it */
199 *((uint32_t *)(kernel + app_dtb_offset)) = 0;
200 return tags;
201 }
202
Dima Zavinc46f8382013-05-03 12:23:06 -0700203 dprintf(CRITICAL, "DTB offset is incorrect, kernel image does not have appended DTB\n");
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800204
Dima Zavin77e41f32013-03-06 16:10:43 -0800205 return NULL;
Channagoud Kadabi11682e92013-02-28 11:21:46 -0800206}
207
Joel Kingaa335dc2013-06-03 16:11:08 -0700208/* Returns 0 if the device tree is valid. */
Deepa Dinamani87252952013-09-09 13:58:27 -0700209int dev_tree_validate(struct dt_table *table, unsigned int page_size, uint32_t *dt_hdr_size)
Joel Kingaa335dc2013-06-03 16:11:08 -0700210{
211 int dt_entry_size;
Channagoud Kadabi49b69332014-06-20 15:41:55 -0700212 uint64_t hdr_size;
Joel Kingaa335dc2013-06-03 16:11:08 -0700213
214 /* Validate the device tree table header */
215 if(table->magic != DEV_TREE_MAGIC) {
216 dprintf(CRITICAL, "ERROR: Bad magic in device tree table \n");
217 return -1;
218 }
219
220 if (table->version == DEV_TREE_VERSION_V1) {
221 dt_entry_size = sizeof(struct dt_entry_v1);
222 } else if (table->version == DEV_TREE_VERSION_V2) {
223 dt_entry_size = sizeof(struct dt_entry);
224 } else {
225 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
226 table->version);
227 return -1;
228 }
229
Channagoud Kadabi49b69332014-06-20 15:41:55 -0700230 hdr_size = (uint64_t)table->num_entries * dt_entry_size + DEV_TREE_HEADER_SIZE;
231
Deepa Dinamani87252952013-09-09 13:58:27 -0700232 /* Roundup to page_size. */
233 hdr_size = ROUNDUP(hdr_size, page_size);
234
Channagoud Kadabi49b69332014-06-20 15:41:55 -0700235 if (hdr_size > UINT_MAX)
236 return -1;
237 else
238 *dt_hdr_size = hdr_size & UINT_MAX;
Joel Kingaa335dc2013-06-03 16:11:08 -0700239
240 return 0;
241}
242
Maria Yu2e2d2c22013-07-03 19:20:33 +0800243static int platform_dt_match(struct dt_entry *cur_dt_entry, uint32_t target_variant_id, uint32_t subtype_mask)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700244{
Maria Yu2e2d2c22013-07-03 19:20:33 +0800245 /* 1. must match the platform_id, hardware_id, platform_version
246 * 2. soc rev number equal then return 0
247 * 3. dt soc rev number less than cdt return -1
248 * 4. otherwise return 1
249 */
250 uint32_t cur_dt_target_id ;
Maria Yuca51ee22013-06-27 21:45:24 +0800251
Maria Yu2e2d2c22013-07-03 19:20:33 +0800252 cur_dt_target_id = cur_dt_entry->variant_id | ((cur_dt_entry->board_hw_subtype & subtype_mask & 0xff) << 24);
253
254 if((cur_dt_entry->platform_id == board_platform_id()) &&
255 (cur_dt_target_id == target_variant_id)) {
256 if(cur_dt_entry->soc_rev == board_soc_version()) {
Maria Yuca51ee22013-06-27 21:45:24 +0800257 return 0;
Maria Yu2e2d2c22013-07-03 19:20:33 +0800258 } else if(cur_dt_entry->soc_rev < board_soc_version()) {
259 return -1;
Maria Yuca51ee22013-06-27 21:45:24 +0800260 }
261 }
Maria Yuca51ee22013-06-27 21:45:24 +0800262
Maria Yu2e2d2c22013-07-03 19:20:33 +0800263 return 1;
Maria Yuca51ee22013-06-27 21:45:24 +0800264}
265
Maria Yu2e2d2c22013-07-03 19:20:33 +0800266static int __dev_tree_get_entry_info(struct dt_table *table, struct dt_entry *dt_entry_info,
267 uint32_t target_variant_id, uint32_t subtype_mask)
Maria Yuca51ee22013-06-27 21:45:24 +0800268{
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700269 uint32_t i;
Joel Kingaa335dc2013-06-03 16:11:08 -0700270 unsigned char *table_ptr;
271 struct dt_entry dt_entry_buf_1;
272 struct dt_entry dt_entry_buf_2;
273 struct dt_entry *cur_dt_entry;
274 struct dt_entry *best_match_dt_entry;
275 struct dt_entry_v1 *dt_entry_v1;
Maria Yu2e2d2c22013-07-03 19:20:33 +0800276 uint32_t found = 0;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700277
Joel Kingaa335dc2013-06-03 16:11:08 -0700278 if (!dt_entry_info) {
279 dprintf(CRITICAL, "ERROR: Bad parameter passed to %s \n",
280 __func__);
281 return -1;
282 }
283
284 table_ptr = (unsigned char *)table + DEV_TREE_HEADER_SIZE;
285 cur_dt_entry = &dt_entry_buf_1;
286 best_match_dt_entry = NULL;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700287
Maria Yu2e2d2c22013-07-03 19:20:33 +0800288 for(i = 0; found == 0 && i < table->num_entries; i++)
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700289 {
Joel Kingaa335dc2013-06-03 16:11:08 -0700290 memset(cur_dt_entry, 0, sizeof(struct dt_entry));
291 switch(table->version) {
292 case DEV_TREE_VERSION_V1:
293 dt_entry_v1 = (struct dt_entry_v1 *)table_ptr;
294 cur_dt_entry->platform_id = dt_entry_v1->platform_id;
295 cur_dt_entry->variant_id = dt_entry_v1->variant_id;
296 cur_dt_entry->soc_rev = dt_entry_v1->soc_rev;
297 cur_dt_entry->board_hw_subtype = board_hardware_subtype();
298 cur_dt_entry->offset = dt_entry_v1->offset;
299 cur_dt_entry->size = dt_entry_v1->size;
300 table_ptr += sizeof(struct dt_entry_v1);
301 break;
302 case DEV_TREE_VERSION_V2:
303 memcpy(cur_dt_entry, (struct dt_entry *)table_ptr,
304 sizeof(struct dt_entry));
305 table_ptr += sizeof(struct dt_entry);
306 break;
307 default:
308 dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
309 table->version);
310 return -1;
311 }
312
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -0800313 /* DTBs are stored in the ascending order of soc revision.
314 * For eg: Rev0..Rev1..Rev2 & so on.
315 * we pickup the DTB with highest soc rev number which is less
316 * than or equal to actual hardware
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700317 */
Maria Yu2e2d2c22013-07-03 19:20:33 +0800318 switch(platform_dt_match(cur_dt_entry, target_variant_id, subtype_mask)) {
319 case 0:
320 best_match_dt_entry = cur_dt_entry;
321 found = 1;
322 break;
323 case -1:
324 if (!best_match_dt_entry) {
325 /* copy structure */
David Ng618293a2013-06-25 12:29:03 -0700326 best_match_dt_entry = cur_dt_entry;
Maria Yu2e2d2c22013-07-03 19:20:33 +0800327 cur_dt_entry = &dt_entry_buf_2;
328 } else {
329 /* Swap dt_entry buffers */
330 struct dt_entry *temp = cur_dt_entry;
331 cur_dt_entry = best_match_dt_entry;
332 best_match_dt_entry = temp;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700333 }
Maria Yu2e2d2c22013-07-03 19:20:33 +0800334 default:
335 break;
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -0800336 }
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700337 }
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -0800338
Joel Kingaa335dc2013-06-03 16:11:08 -0700339 if (best_match_dt_entry) {
340 *dt_entry_info = *best_match_dt_entry;
Maria Yu2e2d2c22013-07-03 19:20:33 +0800341 found = 1;
342 }
343
344 if (found != 0) {
David Ng618293a2013-06-25 12:29:03 -0700345 dprintf(INFO, "Using DTB entry %u/%08x/%u/%u for device %u/%08x/%u/%u\n",
346 dt_entry_info->platform_id, dt_entry_info->soc_rev,
347 dt_entry_info->variant_id, dt_entry_info->board_hw_subtype,
348 board_platform_id(), board_soc_version(),
349 board_hardware_id(), board_hardware_subtype());
Joel Kingaa335dc2013-06-03 16:11:08 -0700350 return 0;
Channagoud Kadabiafd62bf2013-01-08 20:32:52 -0800351 }
352
David Ng618293a2013-06-25 12:29:03 -0700353 dprintf(CRITICAL, "ERROR: Unable to find suitable device tree for device (%u/0x%08x/%u/%u)\n",
354 board_platform_id(), board_soc_version(),
355 board_hardware_id(), board_hardware_subtype());
Joel Kingaa335dc2013-06-03 16:11:08 -0700356 return -1;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700357}
358
Maria Yu2e2d2c22013-07-03 19:20:33 +0800359/* Function to obtain the index information for the correct device tree
360 * based on the platform data.
361 * If a matching device tree is found, the information is returned in the
362 * "dt_entry_info" out parameter and a function value of 0 is returned, otherwise
363 * a non-zero function value is returned.
364 */
365int dev_tree_get_entry_info(struct dt_table *table, struct dt_entry *dt_entry_info)
366{
367 uint32_t target_variant_id;
368
369 if(board_hardware_id() == HW_PLATFORM_QRD) {
370 target_variant_id = board_target_id();
371 if (__dev_tree_get_entry_info(table, dt_entry_info, target_variant_id, 0xff) == 0) {
372 return 0;
373 }
374 }
375 /*
376 * for compatible with version 1 and version 2 dtbtool
377 * will compare the subtype inside the variant id
378 */
379 target_variant_id = board_hardware_id() | ((board_hardware_subtype() & 0xff) << 24);
380 if (__dev_tree_get_entry_info(table, dt_entry_info, target_variant_id, 0xff) == 0) {
381 return 0;
382 }
383
384 /*
385 * add compatible with old device selection method which don't compare subtype
386 */
387 target_variant_id = board_hardware_id();
388 return __dev_tree_get_entry_info(table, dt_entry_info, target_variant_id, 0);
389}
390
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700391/* Function to add the first RAM partition info to the device tree.
392 * Note: The function replaces the reg property in the "/memory" node
393 * with the addr and size provided.
394 */
395int dev_tree_add_first_mem_info(uint32_t *fdt, uint32_t offset, uint32_t addr, uint32_t size)
396{
397 int ret;
398
399 ret = fdt_setprop_u32(fdt, offset, "reg", addr);
400
401 if (ret)
402 {
403 dprintf(CRITICAL, "Failed to add the memory information addr: %d\n",
404 ret);
405 }
406
407
408 ret = fdt_appendprop_u32(fdt, offset, "reg", size);
409
410 if (ret)
411 {
412 dprintf(CRITICAL, "Failed to add the memory information size: %d\n",
413 ret);
414 }
415
416 return ret;
417}
418
419/* Function to add the subsequent RAM partition info to the device tree. */
420int dev_tree_add_mem_info(void *fdt, uint32_t offset, uint32_t addr, uint32_t size)
421{
422 static int mem_info_cnt = 0;
423 int ret;
424
425 if (!mem_info_cnt)
426 {
427 /* Replace any other reg prop in the memory node. */
428 ret = fdt_setprop_u32(fdt, offset, "reg", addr);
429 mem_info_cnt = 1;
430 }
431 else
432 {
433 /* Append the mem info to the reg prop for subsequent nodes. */
434 ret = fdt_appendprop_u32(fdt, offset, "reg", addr);
435 }
436
437 if (ret)
438 {
439 dprintf(CRITICAL, "Failed to add the memory information addr: %d\n",
440 ret);
441 }
442
443
444 ret = fdt_appendprop_u32(fdt, offset, "reg", size);
445
446 if (ret)
447 {
448 dprintf(CRITICAL, "Failed to add the memory information size: %d\n",
449 ret);
450 }
451
452 return ret;
453}
454
455/* Top level function that updates the device tree. */
456int update_device_tree(void *fdt, const char *cmdline,
457 void *ramdisk, uint32_t ramdisk_size)
458{
459 int ret = 0;
460 uint32_t offset;
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700461
462 /* Check the device tree header */
463 ret = fdt_check_header(fdt);
464 if (ret)
465 {
466 dprintf(CRITICAL, "Invalid device tree header \n");
467 return ret;
468 }
469
Deepa Dinamani1c970732013-04-19 14:23:01 -0700470 /* Add padding to make space for new nodes and properties. */
471 ret = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + DTB_PAD_SIZE);
472 if (ret!= 0)
473 {
474 dprintf(CRITICAL, "Failed to move/resize dtb buffer: %d\n", ret);
475 return ret;
476 }
477
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700478 /* Get offset of the memory node */
479 ret = fdt_path_offset(fdt, "/memory");
480 if (ret < 0)
481 {
482 dprintf(CRITICAL, "Could not find memory node.\n");
483 return ret;
484 }
485
486 offset = ret;
487
488 ret = target_dev_tree_mem(fdt, offset);
489 if(ret)
490 {
491 dprintf(CRITICAL, "ERROR: Cannot update memory node\n");
492 return ret;
493 }
494
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700495 /* Get offset of the chosen node */
496 ret = fdt_path_offset(fdt, "/chosen");
497 if (ret < 0)
498 {
499 dprintf(CRITICAL, "Could not find chosen node.\n");
500 return ret;
501 }
502
503 offset = ret;
504 /* Adding the cmdline to the chosen node */
Amol Jadi10c7d1c2013-01-25 13:24:29 -0800505 ret = fdt_setprop_string(fdt, offset, (const char*)"bootargs", (const void*)cmdline);
Deepa Dinamani28c0ffe2012-09-24 11:45:21 -0700506 if (ret)
507 {
508 dprintf(CRITICAL, "ERROR: Cannot update chosen node [bootargs]\n");
509 return ret;
510 }
511
512 /* Adding the initrd-start to the chosen node */
513 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-start", (uint32_t)ramdisk);
514 if (ret)
515 {
516 dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-start]\n");
517 return ret;
518 }
519
520 /* Adding the initrd-end to the chosen node */
521 ret = fdt_setprop_u32(fdt, offset, "linux,initrd-end", ((uint32_t)ramdisk + ramdisk_size));
522 if (ret)
523 {
524 dprintf(CRITICAL, "ERROR: Cannot update chosen node [linux,initrd-end]\n");
525 return ret;
526 }
527
528 fdt_pack(fdt);
529
530 return ret;
531}
Maria Yuca51ee22013-06-27 21:45:24 +0800532