bootmode: remove build warnings
[profile/mobile/platform/kernel/u-boot-tm1.git] / property / dev_tree.c
1 /* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
2  *
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 <common.h>
30 #include <libfdt.h>
31 #include <config.h>
32 #include "dev_tree.h"
33 //#include <lib/ptable.h>
34 #include <malloc.h>
35 //#include <qpic_nand.h>
36 //#include <stdlib.h>
37 //#include <string.h>
38 //#include <platform.h>
39 //#include <board.h>
40
41 #define DEBUG
42
43 #ifdef DEBUG
44 #define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt, ##args); } while (0)
45 #else
46 #define debugf(fmt, args...)
47 #endif
48
49 //extern uint32_t target_dev_tree_mem(void *fdt, uint32_t memory_node_offset);
50 extern int hw_revision;
51 uint32_t target_dev_tree_mem(void *fdt, uint32_t memory_node_offset)
52 {
53         return -1;
54 }
55 #if 0
56 /* TODO: This function needs to be moved to target layer to check violations
57  * against all the other regions as well.
58  */
59 extern int check_aboot_addr_range_overlap(uint32_t start, uint32_t size);
60
61 /*
62  * Will relocate the DTB to the tags addr if the device tree is found and return
63  * its address
64  *
65  * Arguments:    kernel - Start address of the kernel loaded in RAM
66  *               tags - Start address of the tags loaded in RAM
67  *               kernel_size - Size of the kernel in bytes
68  *
69  * Return Value: DTB address : If appended device tree is found
70  *               'NULL'         : Otherwise
71  */
72 void *dev_tree_appended(void *kernel, void *tags, uint32_t kernel_size)
73 {
74         uint32_t app_dtb_offset = 0;
75         uint32_t size;
76
77         memcpy((void*) &app_dtb_offset, (void*) (kernel + DTB_OFFSET), sizeof(uint32_t));
78
79         /*
80          * Check if we have valid offset for the DTB, if not return error.
81          * If the kernel image does not have appeneded device tree, DTB offset
82          * might contain some random address which is not accessible & cause
83          * data abort. If kernel start + dtb offset address exceed the total
84          * size of the kernel, then we dont have an appeneded DTB.
85          */
86         if (app_dtb_offset < kernel_size)
87         {
88                 if (!fdt_check_header((void*) (kernel + app_dtb_offset)))
89                 {
90                         void *dtb;
91                         int rc;
92
93                         debugf( "Found Appeneded Flattened Device tree\n");
94                         dtb = kernel + app_dtb_offset;
95                         size = fdt_totalsize(dtb);
96                         if (check_aboot_addr_range_overlap(tags, size))
97                         {
98                                 debugf("Appended dtb aboot overlap check failed.\n");
99                                 return NULL;
100                         }
101                         rc = fdt_open_into(dtb, tags, size);
102                         if (rc == 0)
103                         {
104                                 /* clear out the old DTB magic so kernel doesn't find it */
105                                 *((uint32_t *)dtb) = 0;
106                                 return tags;
107                         }
108                 }
109         }
110         else
111                 debugf( "DTB offset is incorrect, kernel image does not have appended DTB\n");
112
113         return NULL;
114 }
115 #endif
116 /* Function to return the pointer to the start of the correct device tree
117  *  based on the platform data.
118  */
119 struct dt_entry * dev_tree_get_entry_ptr(struct dt_table *table)
120 {
121         uint32_t i;
122         struct dt_entry *dt_entry_ptr;
123         struct dt_entry *latest_dt_entry = NULL;
124
125         dt_entry_ptr = (struct dt_entry *)((char *)table + DEV_TREE_HEADER_SIZE);
126
127         debugf("magic=%x,ver=%d,num=%d\n",table->magic,table->version,table->num_entries);
128
129 #ifndef CONFIG_MULTI_DTS
130         hw_revision = DT_HARDWARE_ID;
131 #endif
132         debugf("detected hw_rev=%x\n", hw_revision);
133
134         for(i = 0; i < table->num_entries; i++)
135         {
136                 debugf("platform_id=%d, hw_rev=%x, soc_rev=%x\n",
137                         dt_entry_ptr->platform_id,dt_entry_ptr->variant_id,
138                         dt_entry_ptr->soc_rev);
139
140                 /* DTBs are stored in the ascending order of soc revision.
141                  * For eg: Rev0..Rev1..Rev2 & so on.
142                  * we pickup the DTB with highest soc rev number which is less
143                  * than or equal to actual hardware
144                  */
145                 if((dt_entry_ptr->platform_id == DT_PLATFROM_ID) &&
146                    (dt_entry_ptr->variant_id == hw_revision) &&
147                    (dt_entry_ptr->soc_rev == DT_SOC_VER))
148                         {
149                                 debugf("Find matched DTB hw_rev=%x\n",
150                                         dt_entry_ptr->variant_id);
151                                 return dt_entry_ptr;
152                         }
153
154                 /* SLP kernel DT SOC VER check */
155                 if((dt_entry_ptr->platform_id == DT_PLATFROM_ID) &&
156                    (dt_entry_ptr->variant_id == hw_revision) &&
157                    (dt_entry_ptr->soc_rev == DT_SLP_SOC_VER))
158                         {
159                                 debugf("Find matched DTB hw_rev=%x\n",
160                                         dt_entry_ptr->variant_id);
161                                 return dt_entry_ptr;
162                         }
163
164
165                 /* if the exact match not found, return the closest match
166                  * assuming it to be the nearest soc version
167                  */
168                 if((dt_entry_ptr->platform_id == DT_PLATFROM_ID) &&
169                   (dt_entry_ptr->variant_id <= hw_revision) &&
170                   (dt_entry_ptr->soc_rev <= DT_SOC_VER)) {
171                         latest_dt_entry = dt_entry_ptr;
172                 }
173                 dt_entry_ptr++;
174         }
175
176         if (latest_dt_entry) {
177                 debugf( "Loading DTB with SOC version:%x\n", latest_dt_entry->soc_rev);
178                 return latest_dt_entry;
179         }
180
181         return NULL;
182 }
183
184 int load_dtb(int addr,void* dt_img_adr)
185 {
186         struct dt_table *table;
187         struct dt_entry *dt_entry_ptr;
188
189         /* offset now point to start of dt.img */
190         table = (struct dt_table*)dt_img_adr;
191
192         /* Restriction that the device tree entry table should be less than a page*/
193         //ASSERT(((table->num_entries * sizeof(struct dt_entry))+ DEV_TREE_HEADER_SIZE) < hdr->page_size);
194
195         /* Validate the device tree table header */
196         if((table->magic != DEV_TREE_MAGIC) && (table->version != DEV_TREE_VERSION)) {
197                 debugf("ERROR: Cannot validate Device Tree Table %x %u\n", table->magic, table->version);
198                 return -1;
199         }
200
201         /* Calculate the offset of device tree within device tree table */
202         if((dt_entry_ptr = dev_tree_get_entry_ptr(table)) == NULL){
203                 debugf("ERROR: Getting device tree address failed\n");
204                 return -1;
205         }
206
207         /* Validate and Read device device tree in the "tags_add */
208         //if (check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry_ptr->size))
209         //{
210         //      debugf("Device tree addresses overlap with aboot addresses.\n");
211         //      return -1;
212         //}
213
214         memcpy((void*)addr,(const void*)(dt_img_adr +  dt_entry_ptr->offset), dt_entry_ptr->size);
215
216         return 0;
217 }
218
219
220 #if 0
221 /* Function to add the first RAM partition info to the device tree.
222  * Note: The function replaces the reg property in the "/memory" node
223  * with the addr and size provided.
224  */
225 int dev_tree_add_first_mem_info(uint32_t *fdt, uint32_t offset, uint32_t addr, uint32_t size)
226 {
227         int ret;
228
229         ret = fdt_setprop_u32(fdt, offset, "reg", addr);
230
231         if (ret)
232         {
233                 debugf( "Failed to add the memory information addr: %d\n",
234                                 ret);
235         }
236
237
238         ret = fdt_appendprop_u32(fdt, offset, "reg", size);
239
240         if (ret)
241         {
242                 debugf( "Failed to add the memory information size: %d\n",
243                                 ret);
244         }
245
246         return ret;
247 }
248
249 /* Function to add the subsequent RAM partition info to the device tree. */
250 int dev_tree_add_mem_info(void *fdt, uint32_t offset, uint32_t addr, uint32_t size)
251 {
252         static int mem_info_cnt = 0;
253         int ret;
254
255         if (!mem_info_cnt)
256         {
257                 /* Replace any other reg prop in the memory node. */
258                 ret = fdt_setprop_u32(fdt, offset, "reg", addr);
259                 mem_info_cnt = 1;
260         }
261         else
262         {
263                 /* Append the mem info to the reg prop for subsequent nodes.  */
264                 ret = fdt_appendprop_u32(fdt, offset, "reg", addr);
265         }
266
267         if (ret)
268         {
269                 debugf( "Failed to add the memory information addr: %d\n",
270                                 ret);
271         }
272
273
274         ret = fdt_appendprop_u32(fdt, offset, "reg", size);
275
276         if (ret)
277         {
278                 debugf( "Failed to add the memory information size: %d\n",
279                                 ret);
280         }
281
282         return ret;
283 }
284
285 /* Top level function that updates the device tree. */
286 int update_device_tree(void *fdt, const char *cmdline,
287                                            void *ramdisk, uint32_t ramdisk_size)
288 {
289         int ret = 0;
290         uint32_t offset;
291
292         /* Check the device tree header */
293         ret = fdt_check_header(fdt);
294         if (ret)
295         {
296                 debugf( "Invalid device tree header \n");
297                 return ret;
298         }
299
300         /* Add padding to make space for new nodes and properties. */
301         ret = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + DTB_PAD_SIZE);
302         if (ret!= 0)
303         {
304                 debugf( "Failed to move/resize dtb buffer: %d\n", ret);
305                 return ret;
306         }
307
308         /* Get offset of the memory node */
309         ret = fdt_path_offset(fdt, "/memory");
310         if (ret < 0)
311         {
312                 debugf( "Could not find memory node.\n");
313                 return ret;
314         }
315
316         offset = ret;
317
318         ret = target_dev_tree_mem(fdt, offset);
319         if(ret)
320         {
321                 debugf( "ERROR: Cannot update memory node\n");
322                 return ret;
323         }
324
325         /* Get offset of the chosen node */
326         ret = fdt_path_offset(fdt, "/chosen");
327         if (ret < 0)
328         {
329                 debugf("Could not find chosen node.\n");
330                 return ret;
331         }
332
333         offset = ret;
334         /* Adding the cmdline to the chosen node */
335         ret = fdt_setprop_string(fdt, offset, (const char*)"bootargs", (const void*)cmdline);
336         if (ret)
337         {
338                 debugf( "ERROR: Cannot update chosen node [bootargs]\n");
339                 return ret;
340         }
341
342         /* Adding the initrd-start to the chosen node */
343         ret = fdt_setprop_u32(fdt, offset, "linux,initrd-start", (uint32_t)ramdisk);
344         if (ret)
345         {
346                 debugf( "ERROR: Cannot update chosen node [linux,initrd-start]\n");
347                 return ret;
348         }
349
350         /* Adding the initrd-end to the chosen node */
351         ret = fdt_setprop_u32(fdt, offset, "linux,initrd-end", ((uint32_t)ramdisk + ramdisk_size));
352         if (ret)
353         {
354                 debugf( "ERROR: Cannot update chosen node [linux,initrd-end]\n");
355                 return ret;
356         }
357
358         fdt_pack(fdt);
359
360         return ret;
361 }
362 #endif