3 * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
5 * Copyright 2010 Freescale Semiconductor, Inc.
7 * See file CREDITS for list of people who contributed to this
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of
13 * the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
27 #include <stdio_dev.h>
28 #include <linux/ctype.h>
29 #include <linux/types.h>
30 #include <asm/global_data.h>
33 #include <fdt_support.h>
35 #include <normal_mode.h>
37 extern PUBLIC phys_size_t get_dram_size_from_gd(void);
38 extern char* get_calibration_parameter(void);
39 extern bool is_calibration_by_uart(void);
40 extern int poweron_by_calibration(void);
43 * fdt_getprop_u32_default - Find a node and return it's property or a default
45 * @fdt: ptr to device tree
47 * @prop: property name
48 * @dflt: default value if the property isn't found
50 * Convenience function to find a node and return it's property or a
51 * default value if it doesn't exist.
53 u32 fdt_getprop_u32_default(void *fdt, const char *path, const char *prop,
59 off = fdt_path_offset(fdt, path);
63 val = fdt_getprop(fdt, off, prop, NULL);
71 * fdt_find_and_setprop: Find a node and set it's property
73 * @fdt: ptr to device tree
75 * @prop: property name
76 * @val: ptr to new value
77 * @len: length of new property value
78 * @create: flag to create the property if it doesn't exist
80 * Convenience function to directly set a property given the path to the node.
82 int fdt_find_and_setprop(void *fdt, const char *node, const char *prop,
83 const void *val, int len, int create)
85 int nodeoff = fdt_path_offset(fdt, node);
90 if ((!create) && (fdt_get_property(fdt, nodeoff, prop, 0) == NULL))
91 return 0; /* create flag not set; so exit quietly */
93 return fdt_setprop(fdt, nodeoff, prop, val, len);
96 #ifdef CONFIG_OF_STDOUT_VIA_ALIAS
98 #ifdef CONFIG_SERIAL_MULTI
99 static void fdt_fill_multisername(char *sername, size_t maxlen)
101 const char *outname = stdio_devices[stdout]->name;
103 if (strcmp(outname, "serial") > 0)
104 strncpy(sername, outname, maxlen);
107 if (strcmp(outname + 1, "serial") > 0)
108 strncpy(sername, outname + 1, maxlen);
111 static inline void fdt_fill_multisername(char *sername, size_t maxlen) {}
112 #endif /* CONFIG_SERIAL_MULTI */
114 static int fdt_fixup_stdout(void *fdt, int chosenoff)
117 #ifdef CONFIG_CONS_INDEX
119 char sername[9] = { 0 };
122 fdt_fill_multisername(sername, sizeof(sername) - 1);
124 sprintf(sername, "serial%d", CONFIG_CONS_INDEX - 1);
126 err = node = fdt_path_offset(fdt, "/aliases");
129 path = fdt_getprop(fdt, node, sername, &len);
131 char *p = malloc(len);
132 err = -FDT_ERR_NOSPACE;
134 memcpy(p, path, len);
135 err = fdt_setprop(fdt, chosenoff,
136 "linux,stdout-path", p, len);
145 printf("WARNING: could not set linux,stdout-path %s.\n",
152 int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end, int force)
160 /* Find the "chosen" node. */
161 nodeoffset = fdt_path_offset (fdt, "/chosen");
162 /* If there is no "chosen" node in the blob return */
163 if (nodeoffset < 0) {
164 printf("fdt_initrd: %s\n", fdt_strerror(nodeoffset));
168 /* just return if initrd_start/end aren't valid */
169 if ((initrd_start == 0) || (initrd_end == 0))
172 total = fdt_num_mem_rsv(fdt);
175 * Look for an existing entry and update it. If we don't find
176 * the entry, we will j be the next available slot.
178 for (j = 0; j < total; j++) {
179 err = fdt_get_mem_rsv(fdt, j, &addr, &size);
180 if (addr == initrd_start) {
181 fdt_del_mem_rsv(fdt, j);
186 err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start + 1);
188 printf("fdt_initrd: %s\n", fdt_strerror(err));
192 path = fdt_getprop(fdt, nodeoffset, "linux,initrd-start", NULL);
193 if ((path == NULL) || force) {
194 tmp = __cpu_to_be32(initrd_start);
195 err = fdt_setprop(fdt, nodeoffset,
196 "linux,initrd-start", &tmp, sizeof(tmp));
199 "could not set linux,initrd-start %s.\n",
203 tmp = __cpu_to_be32(initrd_end);
204 err = fdt_setprop(fdt, nodeoffset,
205 "linux,initrd-end", &tmp, sizeof(tmp));
207 printf("WARNING: could not set linux,initrd-end %s.\n",
217 int fdt_initrd_norsvmem(void *fdt, ulong initrd_start, ulong initrd_end, int force)
224 /* Find the "chosen" node. */
225 nodeoffset = fdt_path_offset (fdt, "/chosen");
227 /* If there is no "chosen" node in the blob return */
228 if (nodeoffset < 0) {
229 printf("fdt_initrd: %s\n", fdt_strerror(nodeoffset));
233 /* just return if initrd_start/end aren't valid */
234 if ((initrd_start == 0) || (initrd_end == 0))
237 path = fdt_getprop(fdt, nodeoffset, "linux,initrd-start", NULL);
238 if ((path == NULL) || force) {
239 tmp = __cpu_to_be32(initrd_start);
240 err = fdt_setprop(fdt, nodeoffset,
241 "linux,initrd-start", &tmp, sizeof(tmp));
244 "could not set linux,initrd-start %s.\n",
248 tmp = __cpu_to_be32(initrd_end);
249 err = fdt_setprop(fdt, nodeoffset,
250 "linux,initrd-end", &tmp, sizeof(tmp));
252 printf("WARNING: could not set linux,initrd-end %s.\n",
262 int fdt_chosen(void *fdt, int force)
266 char *str; /* used to set string properties */
269 err = fdt_check_header(fdt);
271 printf("fdt_chosen: %s\n", fdt_strerror(err));
276 * Find the "chosen" node.
278 nodeoffset = fdt_path_offset (fdt, "/chosen");
280 * If there is no "chosen" node in the blob, create it.
282 if (nodeoffset < 0) {
284 * Create a new node "/chosen" (offset 0 is root level)
286 nodeoffset = fdt_add_subnode(fdt, 0, "chosen");
287 if (nodeoffset < 0) {
288 printf("WARNING: could not create /chosen %s.\n",
289 fdt_strerror(nodeoffset));
295 * Create /chosen properites that don't exist in the fdt.
296 * If the property exists, update it only if the "force" parameter
299 str = getenv("bootargs");
301 path = fdt_getprop(fdt, nodeoffset, "bootargs", NULL);
302 if ((path == NULL) || force) {
303 err = fdt_setprop(fdt, nodeoffset,
304 "bootargs", str, strlen(str)+1);
306 printf("WARNING: could not set bootargs %s.\n",
311 #ifdef CONFIG_OF_STDOUT_VIA_ALIAS
312 path = fdt_getprop(fdt, nodeoffset, "linux,stdout-path", NULL);
313 if ((path == NULL) || force)
314 err = fdt_fixup_stdout(fdt, nodeoffset);
317 #ifdef OF_STDOUT_PATH
318 path = fdt_getprop(fdt, nodeoffset, "linux,stdout-path", NULL);
319 if ((path == NULL) || force) {
320 err = fdt_setprop(fdt, nodeoffset,
321 "linux,stdout-path", OF_STDOUT_PATH, strlen(OF_STDOUT_PATH)+1);
323 printf("WARNING: could not set linux,stdout-path %s.\n",
331 int fdt_chosen_bootargs_replace(void *fdt, char *old_args, char *new_args)
336 const char *src, *path;
339 if (!old_args || !new_args)
342 err = fdt_check_header(fdt);
344 printf("fdt_chosen_bootargs_replace: %s\n", fdt_strerror(err));
349 * Find the "chosen" node.
351 nodeoffset = fdt_path_offset(fdt, "/chosen");
354 * If there is no "chosen" node in the blob, leave.
356 if (nodeoffset < 0) {
357 printf("fdt_chosen_bootargs_replace: cann't find chosen");
362 * If the property exists, update it only if the "force" parameter
365 path = fdt_getprop(fdt, nodeoffset, "bootargs", NULL);
367 str = strstr(path, old_args);
370 printf("fdt_chosen_bootargs_replace: cann't find str %s!", old_args);
373 strargs = malloc(1024);
379 /* copy the front str */
380 while(src != str && i < 1023){
385 /* copy the new str */
387 while(*src && i < 1023){
392 /* copy the back str */
393 src = str + strlen(old_args);
394 while(*src && i < 1023){
400 printf("fdt_chosen_bootargs_replace: new bootargs %s!", strargs);
401 err = fdt_setprop(fdt, nodeoffset, "bootargs", strargs, strlen(strargs) + 1);
403 printf("WARNING: could not set bootargs %s.\n", fdt_strerror(err));
410 int fdt_chosen_bootargs_append(void *fdt, char* append_args,int force)
420 err = fdt_check_header(fdt);
422 printf("fdt_chosen_bootargs_append: %s\n", fdt_strerror(err));
427 * Find the "chosen" node.
429 nodeoffset = fdt_path_offset (fdt, "/chosen");
432 * If there is no "chosen" node in the blob, leave.
434 if (nodeoffset < 0) {
435 printf("fdt_chosen_bootargs_append: cann't find chosen");
440 * If the property exists, update it only if the "force" parameter
443 path = fdt_getprop(fdt, nodeoffset, "bootargs", NULL);
444 if ((path == NULL) || force) {
445 strargs = malloc(1024);
448 memset(strargs, 0, 1024);
451 sprintf(strargs, "%s %s", path, append_args);
455 sprintf(strargs, "%s", append_args);
457 err = fdt_setprop(fdt, nodeoffset,
458 "bootargs", strargs, strlen(strargs)+1);
460 printf("WARNING: could not set bootargs %s.\n",
468 int fdt_fixup_lcdid(void *fdt)
471 extern uint32_t load_lcd_id_to_kernel(void);
476 lcd_id = load_lcd_id_to_kernel();
479 sprintf(buf, "lcd_id=ID");
480 str_len = strlen(buf);
481 sprintf(&buf[str_len], "%x",lcd_id);
482 str_len = strlen(buf);
485 ret = fdt_chosen_bootargs_append(fdt, buf, 1);
489 int fdt_fixup_lcdbase(void *fdt)
494 extern void *lcd_base;
498 //add lcd frame buffer base, length should be lcd w*h*2(RGB565)
499 sprintf(buf, "lcd_base=");
500 str_len = strlen(buf);
501 sprintf(&buf[str_len], "%lx",(unsigned long)lcd_base);
502 str_len = strlen(buf);
505 ret = fdt_chosen_bootargs_append(fdt, buf, 1);
509 int fdt_fixup_calibration_parameter(void *fdt)
514 buf = get_calibration_parameter();
518 printf("warn:nothing transfer to kernel about calibration\n");
522 ret = fdt_chosen_bootargs_append(fdt, buf, 1);
525 /* if is uart calibraton, remove ttys1 console */
526 if(is_calibration_by_uart())
528 //__raw_writel(0x285480, CTL_PIN_BASE + REG_PIN_CTRL2);
529 //ret = fdt_chosen_bootargs_replace(fdt,"console=ttyS1", "console=ttyS3");
530 ret = fdt_chosen_bootargs_replace(fdt,"console=ttyS1", "console=null");
537 int fdt_fixup_serialno(void *fdt)
544 sprintf(buf, " androidboot.serialno=%s", get_product_sn());
545 str_len = strlen(buf);
547 ret = fdt_chosen_bootargs_append(fdt, buf, 1);
550 int fdt_fixup_dram_training(void *fdt)
556 extern PUBLIC int get_dram_cs_number(void);
557 extern PUBLIC int get_dram_cs0_size(void);
558 sprintf(buf, " mem_cs=%d, mem_cs0_sz=%08x",get_dram_cs_number(), get_dram_cs0_size());
559 str_len = strlen(buf);
561 ret = fdt_chosen_bootargs_append(fdt, buf, 1);
565 static inline int fdt_setprop_u32(void *fdt, int nodeoffset, const char *name,
568 val = cpu_to_fdt32(val);
569 return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val));
572 static inline int fdt_appendprop_u32(void *fdt, int nodeoffset,
573 const char *name, uint32_t val)
575 val = cpu_to_fdt32(val);
576 return fdt_appendprop(fdt, nodeoffset, name, &val, sizeof(val));
582 * fix_memory_size() interface which can be fixup memory size, but because of our
583 * device tree is not suitable for the context, for simple, we add a new function. In arm64,
584 * we should discard it. It should be ok now.
586 #ifdef CONFIG_DDR_AUTO_DETECT
587 int fdt_fixup_ddr_size(void *fdt)
592 u32 val = CONFIG_SYS_SDRAM_BASE;
593 u32 dram_size = get_dram_size_from_gd();
595 nodeoffset = fdt_path_offset(fdt, "/memory");
596 printf("nodeoffset = %d\n", nodeoffset);
597 if (nodeoffset < 0) {
598 printf("ERROR: device tree must have /memory node %s.\n", fdt_strerror(nodeoffset));
602 fdt_delprop(fdt, nodeoffset, "reg");
604 err = fdt_setprop_u32(fdt, nodeoffset, "reg", val);
606 printf("ERROR: cannot set /memory node's reg property(addr)!\n");
610 err = fdt_appendprop_u32(fdt, nodeoffset, "reg", (u32)get_dram_size_from_gd());
612 printf("ERROR: cannot set /memory node's reg property(size)!\n");
618 int fdt_fixup_ddr_size(void *fdt)
624 int fdt_fixup_adc_calibration_data(void *fdt)
626 //extern unsigned int *adc_data_to_transfer;
627 unsigned int *adc_data = malloc(64);
628 int ret = read_adc_calibration_data((void *)adc_data,48);
636 if(((adc_data[2]&0xffff) < 4500 )&&((adc_data[2]&0xffff) > 3000)&&
637 ((adc_data[3]&0xffff) < 4500 )&&((adc_data[3]&0xffff) > 3000))
639 str_len = strlen(buf);
640 sprintf(&buf[str_len], " adc_cal=%d,%d",adc_data[2],adc_data[3]);
642 /*just after fgu adc calibration,and no aux adc calibration,need save fgu adc parameters */
643 if((0x00000002 == adc_data[10])&&(0x00000002 & adc_data[11]))
645 str_len = strlen(buf);
646 sprintf(&buf[str_len], " fgu_cal=%d,%d,%d",adc_data[4],adc_data[5],adc_data[6]);
649 str_len = strlen(buf);
651 ret = fdt_chosen_bootargs_append(fdt, buf, 1);
653 printf("read_adc_calibration_data failed\n");
659 int fdt_fixup_mtd(void *fdt)
667 sprintf(buf, MTDPARTS_DEFAULT);
668 str_len = strlen(buf);
671 ret = fdt_chosen_bootargs_append(fdt, buf, 1);
675 int fdt_fixup_boot_mode(void *fdt,char * boot_mode)
683 sprintf(buf, boot_mode);
684 str_len = strlen(buf);
687 ret = fdt_chosen_bootargs_append(fdt, buf, 1);
691 int fdt_fixup_boot_ram_log(void *fdt)
693 #ifdef CONFIG_RAM_CONSOLE
700 sprintf(buf, "boot_ram_log=%#010x,%#x", CONFIG_RAM_CONSOLE_START, CONFIG_RAM_CONSOLE_SIZE);
701 str_len = strlen(buf);
704 ret = fdt_chosen_bootargs_append(fdt, buf, 1);
706 /* gerenally, reserved memory should be configured in dts file. Add fixup here to avoid the wide
707 range of change for various boards.
710 printf("failed to append ram log option in bootargs\n");
712 ret = fdt_add_mem_rsv(fdt, CONFIG_RAM_CONSOLE_START, CONFIG_RAM_CONSOLE_SIZE);
720 * You can re-define function void fdt_fixup_chosen_bootargs_board(char *buf, const char *boot_mode, int calibration_mode)
721 * in your u-boot/board/spreadtrum/xxx/openphone.c to override this default function
723 void __attribute__((weak)) fdt_fixup_chosen_bootargs_board(char *buf, const char *boot_mode, int calibration_mode)
726 int fdt_fixup_chosen_bootargs_board_private(void *fdt, const char *boot_mode)
730 memset(buf, 0, sizeof buf);
731 fdt_fixup_chosen_bootargs_board(buf, boot_mode, poweron_by_calibration());
733 ret = fdt_chosen_bootargs_append(fdt, buf, 1);
737 void do_fixup_by_path(void *fdt, const char *path, const char *prop,
738 const void *val, int len, int create)
742 debug("Updating property '%s/%s' = ", path, prop);
743 for (i = 0; i < len; i++)
744 debug(" %.2x", *(u8*)(val+i));
747 int rc = fdt_find_and_setprop(fdt, path, prop, val, len, create);
749 printf("Unable to update property %s:%s, err=%s\n",
750 path, prop, fdt_strerror(rc));
753 void do_fixup_by_path_u32(void *fdt, const char *path, const char *prop,
756 val = cpu_to_fdt32(val);
757 do_fixup_by_path(fdt, path, prop, &val, sizeof(val), create);
760 void do_fixup_by_prop(void *fdt,
761 const char *pname, const void *pval, int plen,
762 const char *prop, const void *val, int len,
768 debug("Updating property '%s' = ", prop);
769 for (i = 0; i < len; i++)
770 debug(" %.2x", *(u8*)(val+i));
773 off = fdt_node_offset_by_prop_value(fdt, -1, pname, pval, plen);
774 while (off != -FDT_ERR_NOTFOUND) {
775 if (create || (fdt_get_property(fdt, off, prop, 0) != NULL))
776 fdt_setprop(fdt, off, prop, val, len);
777 off = fdt_node_offset_by_prop_value(fdt, off, pname, pval, plen);
781 void do_fixup_by_prop_u32(void *fdt,
782 const char *pname, const void *pval, int plen,
783 const char *prop, u32 val, int create)
785 val = cpu_to_fdt32(val);
786 do_fixup_by_prop(fdt, pname, pval, plen, prop, &val, 4, create);
789 void do_fixup_by_compat(void *fdt, const char *compat,
790 const char *prop, const void *val, int len, int create)
795 debug("Updating property '%s' = ", prop);
796 for (i = 0; i < len; i++)
797 debug(" %.2x", *(u8*)(val+i));
800 off = fdt_node_offset_by_compatible(fdt, -1, compat);
801 while (off != -FDT_ERR_NOTFOUND) {
802 if (create || (fdt_get_property(fdt, off, prop, 0) != NULL))
803 fdt_setprop(fdt, off, prop, val, len);
804 off = fdt_node_offset_by_compatible(fdt, off, compat);
808 void do_fixup_by_compat_u32(void *fdt, const char *compat,
809 const char *prop, u32 val, int create)
811 val = cpu_to_fdt32(val);
812 do_fixup_by_compat(fdt, compat, prop, &val, 4, create);
816 * Get cells len in bytes
817 * if #NNNN-cells property is 2 then len is 8
820 static int get_cells_len(void *blob, char *nr_cells_name)
824 cell = fdt_getprop(blob, 0, nr_cells_name, NULL);
825 if (cell && *cell == 2)
832 * Write a 4 or 8 byte big endian cell
834 static void write_cell(u8 *addr, u64 val, int size)
836 int shift = (size - 1) * 8;
838 *addr++ = (val >> shift) & 0xff;
843 int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[], int banks)
846 int addr_cell_len, size_cell_len, len;
850 err = fdt_check_header(blob);
852 printf("%s: %s\n", __FUNCTION__, fdt_strerror(err));
856 /* update, or add and update /memory node */
857 nodeoffset = fdt_path_offset(blob, "/memory");
858 if (nodeoffset < 0) {
859 nodeoffset = fdt_add_subnode(blob, 0, "memory");
861 printf("WARNING: could not create /memory: %s.\n",
862 fdt_strerror(nodeoffset));
865 err = fdt_setprop(blob, nodeoffset, "device_type", "memory",
868 printf("WARNING: could not set %s %s.\n", "device_type",
873 addr_cell_len = get_cells_len(blob, "#address-cells");
874 size_cell_len = get_cells_len(blob, "#size-cells");
876 for (bank = 0, len = 0; bank < banks; bank++) {
877 write_cell(tmp + len, start[bank], addr_cell_len);
878 len += addr_cell_len;
880 write_cell(tmp + len, size[bank], size_cell_len);
881 len += size_cell_len;
884 err = fdt_setprop(blob, nodeoffset, "reg", tmp, len);
886 printf("WARNING: could not set %s %s.\n",
887 "reg", fdt_strerror(err));
893 int fdt_fixup_memory(void *blob, u64 start, u64 size)
895 return fdt_fixup_memory_banks(blob, &start, &size, 1);
898 void fdt_fixup_ethernet(void *fdt)
901 char enet[16], *tmp, *end;
902 char mac[16] = "ethaddr";
904 unsigned char mac_addr[6];
906 node = fdt_path_offset(fdt, "/aliases");
911 while ((tmp = getenv(mac)) != NULL) {
912 sprintf(enet, "ethernet%d", i);
913 path = fdt_getprop(fdt, node, enet, NULL);
915 debug("No alias for %s\n", enet);
916 sprintf(mac, "eth%daddr", ++i);
920 for (j = 0; j < 6; j++) {
921 mac_addr[j] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
923 tmp = (*end) ? end+1 : end;
926 do_fixup_by_path(fdt, path, "mac-address", &mac_addr, 6, 0);
927 do_fixup_by_path(fdt, path, "local-mac-address",
930 sprintf(mac, "eth%daddr", ++i);
934 /* Resize the fdt to its actual size + a bit of padding */
935 int fdt_resize(void *blob)
945 total = fdt_num_mem_rsv(blob);
946 for (i = 0; i < total; i++) {
947 fdt_get_mem_rsv(blob, i, &addr, &size);
948 if (addr == (uint64_t)(u32)blob) {
949 fdt_del_mem_rsv(blob, i);
955 * Calculate the actual size of the fdt
956 * plus the size needed for 5 fdt_add_mem_rsv, one
957 * for the fdt itself and 4 for a possible initrd
958 * ((initrd-start + initrd-end) * 2 (name & value))
960 actualsize = fdt_off_dt_strings(blob) +
961 fdt_size_dt_strings(blob) + 5 * sizeof(struct fdt_reserve_entry);
963 /* Make it so the fdt ends on a page boundary */
964 actualsize = ALIGN(actualsize + ((uint)blob & 0xfff), 0x1000);
965 actualsize = actualsize - ((uint)blob & 0xfff);
967 /* Change the fdt header to reflect the correct size */
968 fdt_set_totalsize(blob, actualsize);
970 /* Add the new reservation */
971 ret = fdt_add_mem_rsv(blob, (uint)blob, actualsize);
979 #define CONFIG_SYS_PCI_NR_INBOUND_WIN 4
981 #define FDT_PCI_PREFETCH (0x40000000)
982 #define FDT_PCI_MEM32 (0x02000000)
983 #define FDT_PCI_IO (0x01000000)
984 #define FDT_PCI_MEM64 (0x03000000)
986 int fdt_pci_dma_ranges(void *blob, int phb_off, struct pci_controller *hose) {
988 int addrcell, sizecell, len, r;
990 /* sized based on pci addr cells, size-cells, & address-cells */
991 u32 dma_ranges[(3 + 2 + 2) * CONFIG_SYS_PCI_NR_INBOUND_WIN];
993 addrcell = fdt_getprop_u32_default(blob, "/", "#address-cells", 1);
994 sizecell = fdt_getprop_u32_default(blob, "/", "#size-cells", 1);
996 dma_range = &dma_ranges[0];
997 for (r = 0; r < hose->region_count; r++) {
998 u64 bus_start, phys_start, size;
1000 /* skip if !PCI_REGION_SYS_MEMORY */
1001 if (!(hose->regions[r].flags & PCI_REGION_SYS_MEMORY))
1004 bus_start = (u64)hose->regions[r].bus_start;
1005 phys_start = (u64)hose->regions[r].phys_start;
1006 size = (u64)hose->regions[r].size;
1009 if (size >= 0x100000000ull)
1010 dma_range[0] |= FDT_PCI_MEM64;
1012 dma_range[0] |= FDT_PCI_MEM32;
1013 if (hose->regions[r].flags & PCI_REGION_PREFETCH)
1014 dma_range[0] |= FDT_PCI_PREFETCH;
1015 #ifdef CONFIG_SYS_PCI_64BIT
1016 dma_range[1] = bus_start >> 32;
1020 dma_range[2] = bus_start & 0xffffffff;
1022 if (addrcell == 2) {
1023 dma_range[3] = phys_start >> 32;
1024 dma_range[4] = phys_start & 0xffffffff;
1026 dma_range[3] = phys_start & 0xffffffff;
1029 if (sizecell == 2) {
1030 dma_range[3 + addrcell + 0] = size >> 32;
1031 dma_range[3 + addrcell + 1] = size & 0xffffffff;
1033 dma_range[3 + addrcell + 0] = size & 0xffffffff;
1036 dma_range += (3 + addrcell + sizecell);
1039 len = dma_range - &dma_ranges[0];
1041 fdt_setprop(blob, phb_off, "dma-ranges", &dma_ranges[0], len*4);
1047 #ifdef CONFIG_FDT_FIXUP_NOR_FLASH_SIZE
1049 * Provide a weak default function to return the flash bank size.
1050 * There might be multiple non-identical flash chips connected to one
1051 * chip-select, so we need to pass an index as well.
1053 u32 __flash_get_bank_size(int cs, int idx)
1055 extern flash_info_t flash_info[];
1058 * As default, a simple 1:1 mapping is provided. Boards with
1059 * a different mapping need to supply a board specific mapping
1062 return flash_info[cs].size;
1064 u32 flash_get_bank_size(int cs, int idx)
1065 __attribute__((weak, alias("__flash_get_bank_size")));
1068 * This function can be used to update the size in the "reg" property
1069 * of all NOR FLASH device nodes. This is necessary for boards with
1070 * non-fixed NOR FLASH sizes.
1072 int fdt_fixup_nor_flash_size(void *blob)
1074 char compat[][16] = { "cfi-flash", "jedec-flash" };
1077 struct fdt_property *prop;
1081 for (i = 0; i < 2; i++) {
1082 off = fdt_node_offset_by_compatible(blob, -1, compat[i]);
1083 while (off != -FDT_ERR_NOTFOUND) {
1087 * Found one compatible node, so fixup the size
1088 * int its reg properties
1090 prop = fdt_get_property_w(blob, off, "reg", &len);
1092 int tuple_size = 3 * sizeof(reg);
1095 * There might be multiple reg-tuples,
1096 * so loop through them all
1098 reg = reg2 = (u32 *)&prop->data[0];
1099 for (idx = 0; idx < (len / tuple_size); idx++) {
1101 * Update size in reg property
1103 reg[2] = flash_get_bank_size(reg[0],
1107 * Point to next reg tuple
1112 fdt_setprop(blob, off, "reg", reg2, len);
1115 /* Move to next compatible node */
1116 off = fdt_node_offset_by_compatible(blob, off,
1125 int fdt_increase_size(void *fdt, int add_len)
1129 newlen = fdt_totalsize(fdt) + add_len;
1131 /* Open in place with a new len */
1132 return fdt_open_into(fdt, fdt, newlen);
1135 #ifdef CONFIG_FDT_FIXUP_PARTITIONS
1136 #include <jffs2/load_kernel.h>
1137 #include <mtd_node.h>
1144 int fdt_del_subnodes(const void *blob, int parent_offset)
1149 for (ndepth = 0, off = fdt_next_node(blob, parent_offset, &ndepth);
1150 (off >= 0) && (ndepth > 0);
1151 off = fdt_next_node(blob, off, &ndepth)) {
1153 debug("delete %s: offset: %x\n",
1154 fdt_get_name(blob, off, 0), off);
1155 ret = fdt_del_node((void *)blob, off);
1157 printf("Can't delete node: %s\n",
1162 off = parent_offset;
1169 int fdt_del_partitions(void *blob, int parent_offset)
1176 off = fdt_next_node(blob, parent_offset, &ndepth);
1177 if (off > 0 && ndepth == 1) {
1178 prop = fdt_getprop(blob, off, "label", NULL);
1181 * Could not find label property, nand {}; node?
1182 * Check subnode, delete partitions there if any.
1184 return fdt_del_partitions(blob, off);
1186 ret = fdt_del_subnodes(blob, parent_offset);
1188 printf("Can't remove subnodes: %s\n",
1197 int fdt_node_set_part_info(void *blob, int parent_offset,
1198 struct mtd_device *dev)
1200 struct list_head *pentry;
1201 struct part_info *part;
1202 struct reg_cell cell;
1203 int off, ndepth = 0;
1207 ret = fdt_del_partitions(blob, parent_offset);
1212 * Check if it is nand {}; subnode, adjust
1213 * the offset in this case
1215 off = fdt_next_node(blob, parent_offset, &ndepth);
1216 if (off > 0 && ndepth == 1)
1217 parent_offset = off;
1220 list_for_each_prev(pentry, &dev->parts) {
1223 part = list_entry(pentry, struct part_info, link);
1225 debug("%2d: %-20s0x%08x\t0x%08x\t%d\n",
1226 part_num, part->name, part->size,
1227 part->offset, part->mask_flags);
1229 sprintf(buf, "partition@%x", part->offset);
1231 ret = fdt_add_subnode(blob, parent_offset, buf);
1232 if (ret == -FDT_ERR_NOSPACE) {
1233 ret = fdt_increase_size(blob, 512);
1238 } else if (ret < 0) {
1239 printf("Can't add partition node: %s\n",
1245 /* Check MTD_WRITEABLE_CMD flag */
1246 if (part->mask_flags & 1) {
1248 ret = fdt_setprop(blob, newoff, "read_only", NULL, 0);
1249 if (ret == -FDT_ERR_NOSPACE) {
1250 ret = fdt_increase_size(blob, 512);
1259 cell.r0 = cpu_to_fdt32(part->offset);
1260 cell.r1 = cpu_to_fdt32(part->size);
1262 ret = fdt_setprop(blob, newoff, "reg", &cell, sizeof(cell));
1263 if (ret == -FDT_ERR_NOSPACE) {
1264 ret = fdt_increase_size(blob, 512);
1273 ret = fdt_setprop_string(blob, newoff, "label", part->name);
1274 if (ret == -FDT_ERR_NOSPACE) {
1275 ret = fdt_increase_size(blob, 512);
1287 printf("Can't increase blob size: %s\n", fdt_strerror(ret));
1290 printf("Can't add property: %s\n", fdt_strerror(ret));
1295 * Update partitions in nor/nand nodes using info from
1296 * mtdparts environment variable. The nodes to update are
1297 * specified by node_info structure which contains mtd device
1298 * type and compatible string: E. g. the board code in
1299 * ft_board_setup() could use:
1301 * struct node_info nodes[] = {
1302 * { "fsl,mpc5121-nfc", MTD_DEV_TYPE_NAND, },
1303 * { "cfi-flash", MTD_DEV_TYPE_NOR, },
1306 * fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes));
1308 void fdt_fixup_mtdparts(void *blob, void *node_info, int node_info_size)
1310 struct node_info *ni = node_info;
1311 struct mtd_device *dev;
1316 parts = getenv("mtdparts");
1320 if (mtdparts_init() != 0)
1323 for (i = 0; i < node_info_size; i++) {
1325 noff = fdt_node_offset_by_compatible(blob, -1, ni[i].compat);
1326 while (noff != -FDT_ERR_NOTFOUND) {
1327 debug("%s: %s, mtd dev type %d\n",
1328 fdt_get_name(blob, noff, 0),
1329 ni[i].compat, ni[i].type);
1330 dev = device_find(ni[i].type, idx++);
1332 if (fdt_node_set_part_info(blob, noff, dev))
1333 return; /* return on error */
1336 /* Jump to next flash node */
1337 noff = fdt_node_offset_by_compatible(blob, noff,
1344 void fdt_del_node_and_alias(void *blob, const char *alias)
1346 int off = fdt_path_offset(blob, alias);
1351 fdt_del_node(blob, off);
1353 off = fdt_path_offset(blob, "/aliases");
1354 fdt_delprop(blob, off, alias);
1357 /* Helper to read a big number; size is in cells (not bytes) */
1358 static inline u64 of_read_number(const __be32 *cell, int size)
1362 r = (r << 32) | be32_to_cpu(*(cell++));
1366 #define PRu64 "%llx"
1368 /* Max address size we deal with */
1369 #define OF_MAX_ADDR_CELLS 4
1370 #define OF_BAD_ADDR ((u64)-1)
1371 #define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
1376 static void of_dump_addr(const char *s, const u32 *addr, int na)
1380 printf(" %08x", *(addr++));
1384 static void of_dump_addr(const char *s, const u32 *addr, int na) { }
1387 /* Callbacks for bus specific translators */
1390 const char *addresses;
1391 void (*count_cells)(void *blob, int parentoffset,
1392 int *addrc, int *sizec);
1393 u64 (*map)(u32 *addr, const u32 *range,
1394 int na, int ns, int pna);
1395 int (*translate)(u32 *addr, u64 offset, int na);
1398 /* Default translator (generic bus) */
1399 static void of_bus_default_count_cells(void *blob, int parentoffset,
1400 int *addrc, int *sizec)
1405 prop = fdt_getprop(blob, parentoffset, "#address-cells", NULL);
1407 *addrc = be32_to_cpup((u32 *)prop);
1413 prop = fdt_getprop(blob, parentoffset, "#size-cells", NULL);
1415 *sizec = be32_to_cpup((u32 *)prop);
1421 static u64 of_bus_default_map(u32 *addr, const u32 *range,
1422 int na, int ns, int pna)
1426 cp = of_read_number(range, na);
1427 s = of_read_number(range + na + pna, ns);
1428 da = of_read_number(addr, na);
1430 debug("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n",
1433 if (da < cp || da >= (cp + s))
1438 static int of_bus_default_translate(u32 *addr, u64 offset, int na)
1440 u64 a = of_read_number(addr, na);
1441 memset(addr, 0, na * 4);
1444 addr[na - 2] = a >> 32;
1445 addr[na - 1] = a & 0xffffffffu;
1450 /* Array of bus specific translators */
1451 static struct of_bus of_busses[] = {
1456 .count_cells = of_bus_default_count_cells,
1457 .map = of_bus_default_map,
1458 .translate = of_bus_default_translate,
1462 static int of_translate_one(void * blob, int parent, struct of_bus *bus,
1463 struct of_bus *pbus, u32 *addr,
1464 int na, int ns, int pna, const char *rprop)
1469 u64 offset = OF_BAD_ADDR;
1471 /* Normally, an absence of a "ranges" property means we are
1472 * crossing a non-translatable boundary, and thus the addresses
1473 * below the current not cannot be converted to CPU physical ones.
1474 * Unfortunately, while this is very clear in the spec, it's not
1475 * what Apple understood, and they do have things like /uni-n or
1476 * /ht nodes with no "ranges" property and a lot of perfectly
1477 * useable mapped devices below them. Thus we treat the absence of
1478 * "ranges" as equivalent to an empty "ranges" property which means
1479 * a 1:1 translation at that level. It's up to the caller not to try
1480 * to translate addresses that aren't supposed to be translated in
1481 * the first place. --BenH.
1483 ranges = (u32 *)fdt_getprop(blob, parent, rprop, &rlen);
1484 if (ranges == NULL || rlen == 0) {
1485 offset = of_read_number(addr, na);
1486 memset(addr, 0, pna * 4);
1487 debug("OF: no ranges, 1:1 translation\n");
1491 debug("OF: walking ranges...\n");
1493 /* Now walk through the ranges */
1495 rone = na + pna + ns;
1496 for (; rlen >= rone; rlen -= rone, ranges += rone) {
1497 offset = bus->map(addr, ranges, na, ns, pna);
1498 if (offset != OF_BAD_ADDR)
1501 if (offset == OF_BAD_ADDR) {
1502 debug("OF: not found !\n");
1505 memcpy(addr, ranges + na, 4 * pna);
1508 of_dump_addr("OF: parent translation for:", addr, pna);
1509 debug("OF: with offset: "PRu64"\n", offset);
1511 /* Translate it into parent bus space */
1512 return pbus->translate(addr, offset, pna);
1516 * Translate an address from the device-tree into a CPU physical address,
1517 * this walks up the tree and applies the various bus mappings on the
1520 * Note: We consider that crossing any level with #size-cells == 0 to mean
1521 * that translation is impossible (that is we are not dealing with a value
1522 * that can be mapped to a cpu physical address). This is not really specified
1523 * that way, but this is traditionally the way IBM at least do things
1525 u64 __of_translate_address(void *blob, int node_offset, const u32 *in_addr,
1529 struct of_bus *bus, *pbus;
1530 u32 addr[OF_MAX_ADDR_CELLS];
1531 int na, ns, pna, pns;
1532 u64 result = OF_BAD_ADDR;
1534 debug("OF: ** translation for device %s **\n",
1535 fdt_get_name(blob, node_offset, NULL));
1537 /* Get parent & match bus type */
1538 parent = fdt_parent_offset(blob, node_offset);
1541 bus = &of_busses[0];
1543 /* Cound address cells & copy address locally */
1544 bus->count_cells(blob, parent, &na, &ns);
1545 if (!OF_CHECK_COUNTS(na, ns)) {
1546 printf("%s: Bad cell count for %s\n", __FUNCTION__,
1547 fdt_get_name(blob, node_offset, NULL));
1550 memcpy(addr, in_addr, na * 4);
1552 debug("OF: bus is %s (na=%d, ns=%d) on %s\n",
1553 bus->name, na, ns, fdt_get_name(blob, parent, NULL));
1554 of_dump_addr("OF: translating address:", addr, na);
1558 /* Switch to parent bus */
1559 node_offset = parent;
1560 parent = fdt_parent_offset(blob, node_offset);
1562 /* If root, we have finished */
1564 debug("OF: reached root node\n");
1565 result = of_read_number(addr, na);
1569 /* Get new parent bus and counts */
1570 pbus = &of_busses[0];
1571 pbus->count_cells(blob, parent, &pna, &pns);
1572 if (!OF_CHECK_COUNTS(pna, pns)) {
1573 printf("%s: Bad cell count for %s\n", __FUNCTION__,
1574 fdt_get_name(blob, node_offset, NULL));
1578 debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
1579 pbus->name, pna, pns, fdt_get_name(blob, parent, NULL));
1581 /* Apply bus translation */
1582 if (of_translate_one(blob, node_offset, bus, pbus,
1583 addr, na, ns, pna, rprop))
1586 /* Complete the move up one level */
1591 of_dump_addr("OF: one level translation:", addr, na);
1598 u64 fdt_translate_address(void *blob, int node_offset, const u32 *in_addr)
1600 return __of_translate_address(blob, node_offset, in_addr, "ranges");
1604 * fdt_node_offset_by_compat_reg: Find a node that matches compatiable and
1605 * who's reg property matches a physical cpu address
1607 * @blob: ptr to device tree
1608 * @compat: compatiable string to match
1609 * @compat_off: property name
1612 int fdt_node_offset_by_compat_reg(void *blob, const char *compat,
1613 phys_addr_t compat_off)
1615 int len, off = fdt_node_offset_by_compatible(blob, -1, compat);
1616 while (off != -FDT_ERR_NOTFOUND) {
1617 u32 *reg = (u32 *)fdt_getprop(blob, off, "reg", &len);
1619 if (compat_off == fdt_translate_address(blob, off, reg))
1622 off = fdt_node_offset_by_compatible(blob, off, compat);
1625 return -FDT_ERR_NOTFOUND;
1629 * fdt_alloc_phandle: Return next free phandle value
1631 * @blob: ptr to device tree
1633 int fdt_alloc_phandle(void *blob)
1635 int offset, len, phandle = 0;
1638 for (offset = fdt_next_node(blob, -1, NULL); offset >= 0;
1639 offset = fdt_next_node(blob, offset, NULL)) {
1640 val = fdt_getprop(blob, offset, "linux,phandle", &len);
1642 phandle = max(*val, phandle);
1648 #if defined(CONFIG_VIDEO)
1649 int fdt_add_edid(void *blob, const char *compat, unsigned char *edid_buf)
1654 noff = fdt_node_offset_by_compatible(blob, -1, compat);
1655 if (noff != -FDT_ERR_NOTFOUND) {
1656 debug("%s: %s\n", fdt_get_name(blob, noff, 0), compat);
1658 ret = fdt_setprop(blob, noff, "edid", edid_buf, 128);
1659 if (ret == -FDT_ERR_NOSPACE) {
1660 ret = fdt_increase_size(blob, 512);
1665 } else if (ret < 0) {
1666 printf("Can't add property: %s\n", fdt_strerror(ret));
1672 printf("Can't increase blob size: %s\n", fdt_strerror(ret));
1677 void fdt_debug_print_prop(void *fdt, const char *node_path, const char *name)
1685 printf("fdt addr: 0x%lx\n", (unsigned long)fdt);
1687 err = fdt_check_header(fdt);
1689 printf("not found fdt header: %s\n", fdt_strerror(err));
1693 nodeoffset = fdt_path_offset (fdt, node_path);
1695 if (nodeoffset < 0) {
1696 printf("not found %s path\n", node_path);
1700 path = fdt_getprop(fdt, nodeoffset, name, &len);
1703 printf("not found %s prop\n", name);
1707 printf("================\n");
1708 printf("%s/%s: ", node_path, name);
1709 for (i = 0; i < len; i++) {
1710 printf("%c", *(path)++);
1713 printf("================\n");