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);
42 * fdt_getprop_u32_default - Find a node and return it's property or a default
44 * @fdt: ptr to device tree
46 * @prop: property name
47 * @dflt: default value if the property isn't found
49 * Convenience function to find a node and return it's property or a
50 * default value if it doesn't exist.
52 u32 fdt_getprop_u32_default(void *fdt, const char *path, const char *prop,
58 off = fdt_path_offset(fdt, path);
62 val = fdt_getprop(fdt, off, prop, NULL);
70 * fdt_find_and_setprop: Find a node and set it's property
72 * @fdt: ptr to device tree
74 * @prop: property name
75 * @val: ptr to new value
76 * @len: length of new property value
77 * @create: flag to create the property if it doesn't exist
79 * Convenience function to directly set a property given the path to the node.
81 int fdt_find_and_setprop(void *fdt, const char *node, const char *prop,
82 const void *val, int len, int create)
84 int nodeoff = fdt_path_offset(fdt, node);
89 if ((!create) && (fdt_get_property(fdt, nodeoff, prop, 0) == NULL))
90 return 0; /* create flag not set; so exit quietly */
92 return fdt_setprop(fdt, nodeoff, prop, val, len);
95 #ifdef CONFIG_OF_STDOUT_VIA_ALIAS
97 #ifdef CONFIG_SERIAL_MULTI
98 static void fdt_fill_multisername(char *sername, size_t maxlen)
100 const char *outname = stdio_devices[stdout]->name;
102 if (strcmp(outname, "serial") > 0)
103 strncpy(sername, outname, maxlen);
106 if (strcmp(outname + 1, "serial") > 0)
107 strncpy(sername, outname + 1, maxlen);
110 static inline void fdt_fill_multisername(char *sername, size_t maxlen) {}
111 #endif /* CONFIG_SERIAL_MULTI */
113 static int fdt_fixup_stdout(void *fdt, int chosenoff)
116 #ifdef CONFIG_CONS_INDEX
118 char sername[9] = { 0 };
121 fdt_fill_multisername(sername, sizeof(sername) - 1);
123 sprintf(sername, "serial%d", CONFIG_CONS_INDEX - 1);
125 err = node = fdt_path_offset(fdt, "/aliases");
128 path = fdt_getprop(fdt, node, sername, &len);
130 char *p = malloc(len);
131 err = -FDT_ERR_NOSPACE;
133 memcpy(p, path, len);
134 err = fdt_setprop(fdt, chosenoff,
135 "linux,stdout-path", p, len);
144 printf("WARNING: could not set linux,stdout-path %s.\n",
151 int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end, int force)
159 /* Find the "chosen" node. */
160 nodeoffset = fdt_path_offset (fdt, "/chosen");
161 /* If there is no "chosen" node in the blob return */
162 if (nodeoffset < 0) {
163 printf("fdt_initrd: %s\n", fdt_strerror(nodeoffset));
167 /* just return if initrd_start/end aren't valid */
168 if ((initrd_start == 0) || (initrd_end == 0))
171 total = fdt_num_mem_rsv(fdt);
174 * Look for an existing entry and update it. If we don't find
175 * the entry, we will j be the next available slot.
177 for (j = 0; j < total; j++) {
178 err = fdt_get_mem_rsv(fdt, j, &addr, &size);
179 if (addr == initrd_start) {
180 fdt_del_mem_rsv(fdt, j);
185 err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start + 1);
187 printf("fdt_initrd: %s\n", fdt_strerror(err));
191 path = fdt_getprop(fdt, nodeoffset, "linux,initrd-start", NULL);
192 if ((path == NULL) || force) {
193 tmp = __cpu_to_be32(initrd_start);
194 err = fdt_setprop(fdt, nodeoffset,
195 "linux,initrd-start", &tmp, sizeof(tmp));
198 "could not set linux,initrd-start %s.\n",
202 tmp = __cpu_to_be32(initrd_end);
203 err = fdt_setprop(fdt, nodeoffset,
204 "linux,initrd-end", &tmp, sizeof(tmp));
206 printf("WARNING: could not set linux,initrd-end %s.\n",
216 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)
335 char *str, *src, *dst;
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();
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], "%x",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(adc_data,48);
637 if(((adc_data[2]&0xffff) < 4500 )&&((adc_data[2]&0xffff) > 3000)&&
638 ((adc_data[3]&0xffff) < 4500 )&&((adc_data[3]&0xffff) > 3000))
640 str_len = strlen(buf);
641 sprintf(&buf[str_len], " adc_cal=%d,%d",adc_data[2],adc_data[3]);
643 /*just after fgu adc calibration,and no aux adc calibration,need save fgu adc parameters */
644 if((0x00000002 == adc_data[10])&&(0x00000002 & adc_data[11]))
646 str_len = strlen(buf);
647 sprintf(&buf[str_len], " fgu_cal=%d,%d,%d",adc_data[4],adc_data[5],adc_data[6]);
650 str_len = strlen(buf);
652 ret = fdt_chosen_bootargs_append(fdt, buf, 1);
654 printf("read_adc_calibration_data failed\n");
660 int fdt_fixup_mtd(void *fdt)
668 sprintf(buf, MTDPARTS_DEFAULT);
669 str_len = strlen(buf);
672 ret = fdt_chosen_bootargs_append(fdt, buf, 1);
676 int fdt_fixup_boot_mode(void *fdt,char * boot_mode)
684 sprintf(buf, boot_mode);
685 str_len = strlen(buf);
688 ret = fdt_chosen_bootargs_append(fdt, buf, 1);
692 int fdt_fixup_boot_ram_log(void *fdt)
694 #ifdef CONFIG_RAM_CONSOLE
701 sprintf(buf, "boot_ram_log=%#010x,%#x", CONFIG_RAM_CONSOLE_START, CONFIG_RAM_CONSOLE_SIZE);
702 str_len = strlen(buf);
705 ret = fdt_chosen_bootargs_append(fdt, buf, 1);
707 /* gerenally, reserved memory should be configured in dts file. Add fixup here to avoid the wide
708 range of change for various boards.
711 printf("failed to append ram log option in bootargs\n");
713 ret = fdt_add_mem_rsv(fdt, CONFIG_RAM_CONSOLE_START, CONFIG_RAM_CONSOLE_SIZE);
721 * You can re-define function void fdt_fixup_chosen_bootargs_board(char *buf, const char *boot_mode, int calibration_mode)
722 * in your u-boot/board/spreadtrum/xxx/openphone.c to override this default function
724 void __attribute__((weak)) fdt_fixup_chosen_bootargs_board(char *buf, const char *boot_mode, int calibration_mode)
727 int fdt_fixup_chosen_bootargs_board_private(void *fdt, const char *boot_mode)
731 memset(buf, 0, sizeof buf);
732 fdt_fixup_chosen_bootargs_board(buf, boot_mode, poweron_by_calibration());
734 ret = fdt_chosen_bootargs_append(fdt, buf, 1);
738 void do_fixup_by_path(void *fdt, const char *path, const char *prop,
739 const void *val, int len, int create)
743 debug("Updating property '%s/%s' = ", path, prop);
744 for (i = 0; i < len; i++)
745 debug(" %.2x", *(u8*)(val+i));
748 int rc = fdt_find_and_setprop(fdt, path, prop, val, len, create);
750 printf("Unable to update property %s:%s, err=%s\n",
751 path, prop, fdt_strerror(rc));
754 void do_fixup_by_path_u32(void *fdt, const char *path, const char *prop,
757 val = cpu_to_fdt32(val);
758 do_fixup_by_path(fdt, path, prop, &val, sizeof(val), create);
761 void do_fixup_by_prop(void *fdt,
762 const char *pname, const void *pval, int plen,
763 const char *prop, const void *val, int len,
769 debug("Updating property '%s' = ", prop);
770 for (i = 0; i < len; i++)
771 debug(" %.2x", *(u8*)(val+i));
774 off = fdt_node_offset_by_prop_value(fdt, -1, pname, pval, plen);
775 while (off != -FDT_ERR_NOTFOUND) {
776 if (create || (fdt_get_property(fdt, off, prop, 0) != NULL))
777 fdt_setprop(fdt, off, prop, val, len);
778 off = fdt_node_offset_by_prop_value(fdt, off, pname, pval, plen);
782 void do_fixup_by_prop_u32(void *fdt,
783 const char *pname, const void *pval, int plen,
784 const char *prop, u32 val, int create)
786 val = cpu_to_fdt32(val);
787 do_fixup_by_prop(fdt, pname, pval, plen, prop, &val, 4, create);
790 void do_fixup_by_compat(void *fdt, const char *compat,
791 const char *prop, const void *val, int len, int create)
796 debug("Updating property '%s' = ", prop);
797 for (i = 0; i < len; i++)
798 debug(" %.2x", *(u8*)(val+i));
801 off = fdt_node_offset_by_compatible(fdt, -1, compat);
802 while (off != -FDT_ERR_NOTFOUND) {
803 if (create || (fdt_get_property(fdt, off, prop, 0) != NULL))
804 fdt_setprop(fdt, off, prop, val, len);
805 off = fdt_node_offset_by_compatible(fdt, off, compat);
809 void do_fixup_by_compat_u32(void *fdt, const char *compat,
810 const char *prop, u32 val, int create)
812 val = cpu_to_fdt32(val);
813 do_fixup_by_compat(fdt, compat, prop, &val, 4, create);
817 * Get cells len in bytes
818 * if #NNNN-cells property is 2 then len is 8
821 static int get_cells_len(void *blob, char *nr_cells_name)
825 cell = fdt_getprop(blob, 0, nr_cells_name, NULL);
826 if (cell && *cell == 2)
833 * Write a 4 or 8 byte big endian cell
835 static void write_cell(u8 *addr, u64 val, int size)
837 int shift = (size - 1) * 8;
839 *addr++ = (val >> shift) & 0xff;
844 int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[], int banks)
847 int addr_cell_len, size_cell_len, len;
851 err = fdt_check_header(blob);
853 printf("%s: %s\n", __FUNCTION__, fdt_strerror(err));
857 /* update, or add and update /memory node */
858 nodeoffset = fdt_path_offset(blob, "/memory");
859 if (nodeoffset < 0) {
860 nodeoffset = fdt_add_subnode(blob, 0, "memory");
862 printf("WARNING: could not create /memory: %s.\n",
863 fdt_strerror(nodeoffset));
866 err = fdt_setprop(blob, nodeoffset, "device_type", "memory",
869 printf("WARNING: could not set %s %s.\n", "device_type",
874 addr_cell_len = get_cells_len(blob, "#address-cells");
875 size_cell_len = get_cells_len(blob, "#size-cells");
877 for (bank = 0, len = 0; bank < banks; bank++) {
878 write_cell(tmp + len, start[bank], addr_cell_len);
879 len += addr_cell_len;
881 write_cell(tmp + len, size[bank], size_cell_len);
882 len += size_cell_len;
885 err = fdt_setprop(blob, nodeoffset, "reg", tmp, len);
887 printf("WARNING: could not set %s %s.\n",
888 "reg", fdt_strerror(err));
894 int fdt_fixup_memory(void *blob, u64 start, u64 size)
896 return fdt_fixup_memory_banks(blob, &start, &size, 1);
899 void fdt_fixup_ethernet(void *fdt)
902 char enet[16], *tmp, *end;
903 char mac[16] = "ethaddr";
905 unsigned char mac_addr[6];
907 node = fdt_path_offset(fdt, "/aliases");
912 while ((tmp = getenv(mac)) != NULL) {
913 sprintf(enet, "ethernet%d", i);
914 path = fdt_getprop(fdt, node, enet, NULL);
916 debug("No alias for %s\n", enet);
917 sprintf(mac, "eth%daddr", ++i);
921 for (j = 0; j < 6; j++) {
922 mac_addr[j] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
924 tmp = (*end) ? end+1 : end;
927 do_fixup_by_path(fdt, path, "mac-address", &mac_addr, 6, 0);
928 do_fixup_by_path(fdt, path, "local-mac-address",
931 sprintf(mac, "eth%daddr", ++i);
935 /* Resize the fdt to its actual size + a bit of padding */
936 int fdt_resize(void *blob)
946 total = fdt_num_mem_rsv(blob);
947 for (i = 0; i < total; i++) {
948 fdt_get_mem_rsv(blob, i, &addr, &size);
949 if (addr == (uint64_t)(u32)blob) {
950 fdt_del_mem_rsv(blob, i);
956 * Calculate the actual size of the fdt
957 * plus the size needed for 5 fdt_add_mem_rsv, one
958 * for the fdt itself and 4 for a possible initrd
959 * ((initrd-start + initrd-end) * 2 (name & value))
961 actualsize = fdt_off_dt_strings(blob) +
962 fdt_size_dt_strings(blob) + 5 * sizeof(struct fdt_reserve_entry);
964 /* Make it so the fdt ends on a page boundary */
965 actualsize = ALIGN(actualsize + ((uint)blob & 0xfff), 0x1000);
966 actualsize = actualsize - ((uint)blob & 0xfff);
968 /* Change the fdt header to reflect the correct size */
969 fdt_set_totalsize(blob, actualsize);
971 /* Add the new reservation */
972 ret = fdt_add_mem_rsv(blob, (uint)blob, actualsize);
980 #define CONFIG_SYS_PCI_NR_INBOUND_WIN 4
982 #define FDT_PCI_PREFETCH (0x40000000)
983 #define FDT_PCI_MEM32 (0x02000000)
984 #define FDT_PCI_IO (0x01000000)
985 #define FDT_PCI_MEM64 (0x03000000)
987 int fdt_pci_dma_ranges(void *blob, int phb_off, struct pci_controller *hose) {
989 int addrcell, sizecell, len, r;
991 /* sized based on pci addr cells, size-cells, & address-cells */
992 u32 dma_ranges[(3 + 2 + 2) * CONFIG_SYS_PCI_NR_INBOUND_WIN];
994 addrcell = fdt_getprop_u32_default(blob, "/", "#address-cells", 1);
995 sizecell = fdt_getprop_u32_default(blob, "/", "#size-cells", 1);
997 dma_range = &dma_ranges[0];
998 for (r = 0; r < hose->region_count; r++) {
999 u64 bus_start, phys_start, size;
1001 /* skip if !PCI_REGION_SYS_MEMORY */
1002 if (!(hose->regions[r].flags & PCI_REGION_SYS_MEMORY))
1005 bus_start = (u64)hose->regions[r].bus_start;
1006 phys_start = (u64)hose->regions[r].phys_start;
1007 size = (u64)hose->regions[r].size;
1010 if (size >= 0x100000000ull)
1011 dma_range[0] |= FDT_PCI_MEM64;
1013 dma_range[0] |= FDT_PCI_MEM32;
1014 if (hose->regions[r].flags & PCI_REGION_PREFETCH)
1015 dma_range[0] |= FDT_PCI_PREFETCH;
1016 #ifdef CONFIG_SYS_PCI_64BIT
1017 dma_range[1] = bus_start >> 32;
1021 dma_range[2] = bus_start & 0xffffffff;
1023 if (addrcell == 2) {
1024 dma_range[3] = phys_start >> 32;
1025 dma_range[4] = phys_start & 0xffffffff;
1027 dma_range[3] = phys_start & 0xffffffff;
1030 if (sizecell == 2) {
1031 dma_range[3 + addrcell + 0] = size >> 32;
1032 dma_range[3 + addrcell + 1] = size & 0xffffffff;
1034 dma_range[3 + addrcell + 0] = size & 0xffffffff;
1037 dma_range += (3 + addrcell + sizecell);
1040 len = dma_range - &dma_ranges[0];
1042 fdt_setprop(blob, phb_off, "dma-ranges", &dma_ranges[0], len*4);
1048 #ifdef CONFIG_FDT_FIXUP_NOR_FLASH_SIZE
1050 * Provide a weak default function to return the flash bank size.
1051 * There might be multiple non-identical flash chips connected to one
1052 * chip-select, so we need to pass an index as well.
1054 u32 __flash_get_bank_size(int cs, int idx)
1056 extern flash_info_t flash_info[];
1059 * As default, a simple 1:1 mapping is provided. Boards with
1060 * a different mapping need to supply a board specific mapping
1063 return flash_info[cs].size;
1065 u32 flash_get_bank_size(int cs, int idx)
1066 __attribute__((weak, alias("__flash_get_bank_size")));
1069 * This function can be used to update the size in the "reg" property
1070 * of all NOR FLASH device nodes. This is necessary for boards with
1071 * non-fixed NOR FLASH sizes.
1073 int fdt_fixup_nor_flash_size(void *blob)
1075 char compat[][16] = { "cfi-flash", "jedec-flash" };
1078 struct fdt_property *prop;
1082 for (i = 0; i < 2; i++) {
1083 off = fdt_node_offset_by_compatible(blob, -1, compat[i]);
1084 while (off != -FDT_ERR_NOTFOUND) {
1088 * Found one compatible node, so fixup the size
1089 * int its reg properties
1091 prop = fdt_get_property_w(blob, off, "reg", &len);
1093 int tuple_size = 3 * sizeof(reg);
1096 * There might be multiple reg-tuples,
1097 * so loop through them all
1099 reg = reg2 = (u32 *)&prop->data[0];
1100 for (idx = 0; idx < (len / tuple_size); idx++) {
1102 * Update size in reg property
1104 reg[2] = flash_get_bank_size(reg[0],
1108 * Point to next reg tuple
1113 fdt_setprop(blob, off, "reg", reg2, len);
1116 /* Move to next compatible node */
1117 off = fdt_node_offset_by_compatible(blob, off,
1126 int fdt_increase_size(void *fdt, int add_len)
1130 newlen = fdt_totalsize(fdt) + add_len;
1132 /* Open in place with a new len */
1133 return fdt_open_into(fdt, fdt, newlen);
1136 #ifdef CONFIG_FDT_FIXUP_PARTITIONS
1137 #include <jffs2/load_kernel.h>
1138 #include <mtd_node.h>
1145 int fdt_del_subnodes(const void *blob, int parent_offset)
1150 for (ndepth = 0, off = fdt_next_node(blob, parent_offset, &ndepth);
1151 (off >= 0) && (ndepth > 0);
1152 off = fdt_next_node(blob, off, &ndepth)) {
1154 debug("delete %s: offset: %x\n",
1155 fdt_get_name(blob, off, 0), off);
1156 ret = fdt_del_node((void *)blob, off);
1158 printf("Can't delete node: %s\n",
1163 off = parent_offset;
1170 int fdt_del_partitions(void *blob, int parent_offset)
1177 off = fdt_next_node(blob, parent_offset, &ndepth);
1178 if (off > 0 && ndepth == 1) {
1179 prop = fdt_getprop(blob, off, "label", NULL);
1182 * Could not find label property, nand {}; node?
1183 * Check subnode, delete partitions there if any.
1185 return fdt_del_partitions(blob, off);
1187 ret = fdt_del_subnodes(blob, parent_offset);
1189 printf("Can't remove subnodes: %s\n",
1198 int fdt_node_set_part_info(void *blob, int parent_offset,
1199 struct mtd_device *dev)
1201 struct list_head *pentry;
1202 struct part_info *part;
1203 struct reg_cell cell;
1204 int off, ndepth = 0;
1208 ret = fdt_del_partitions(blob, parent_offset);
1213 * Check if it is nand {}; subnode, adjust
1214 * the offset in this case
1216 off = fdt_next_node(blob, parent_offset, &ndepth);
1217 if (off > 0 && ndepth == 1)
1218 parent_offset = off;
1221 list_for_each_prev(pentry, &dev->parts) {
1224 part = list_entry(pentry, struct part_info, link);
1226 debug("%2d: %-20s0x%08x\t0x%08x\t%d\n",
1227 part_num, part->name, part->size,
1228 part->offset, part->mask_flags);
1230 sprintf(buf, "partition@%x", part->offset);
1232 ret = fdt_add_subnode(blob, parent_offset, buf);
1233 if (ret == -FDT_ERR_NOSPACE) {
1234 ret = fdt_increase_size(blob, 512);
1239 } else if (ret < 0) {
1240 printf("Can't add partition node: %s\n",
1246 /* Check MTD_WRITEABLE_CMD flag */
1247 if (part->mask_flags & 1) {
1249 ret = fdt_setprop(blob, newoff, "read_only", NULL, 0);
1250 if (ret == -FDT_ERR_NOSPACE) {
1251 ret = fdt_increase_size(blob, 512);
1260 cell.r0 = cpu_to_fdt32(part->offset);
1261 cell.r1 = cpu_to_fdt32(part->size);
1263 ret = fdt_setprop(blob, newoff, "reg", &cell, sizeof(cell));
1264 if (ret == -FDT_ERR_NOSPACE) {
1265 ret = fdt_increase_size(blob, 512);
1274 ret = fdt_setprop_string(blob, newoff, "label", part->name);
1275 if (ret == -FDT_ERR_NOSPACE) {
1276 ret = fdt_increase_size(blob, 512);
1288 printf("Can't increase blob size: %s\n", fdt_strerror(ret));
1291 printf("Can't add property: %s\n", fdt_strerror(ret));
1296 * Update partitions in nor/nand nodes using info from
1297 * mtdparts environment variable. The nodes to update are
1298 * specified by node_info structure which contains mtd device
1299 * type and compatible string: E. g. the board code in
1300 * ft_board_setup() could use:
1302 * struct node_info nodes[] = {
1303 * { "fsl,mpc5121-nfc", MTD_DEV_TYPE_NAND, },
1304 * { "cfi-flash", MTD_DEV_TYPE_NOR, },
1307 * fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes));
1309 void fdt_fixup_mtdparts(void *blob, void *node_info, int node_info_size)
1311 struct node_info *ni = node_info;
1312 struct mtd_device *dev;
1317 parts = getenv("mtdparts");
1321 if (mtdparts_init() != 0)
1324 for (i = 0; i < node_info_size; i++) {
1326 noff = fdt_node_offset_by_compatible(blob, -1, ni[i].compat);
1327 while (noff != -FDT_ERR_NOTFOUND) {
1328 debug("%s: %s, mtd dev type %d\n",
1329 fdt_get_name(blob, noff, 0),
1330 ni[i].compat, ni[i].type);
1331 dev = device_find(ni[i].type, idx++);
1333 if (fdt_node_set_part_info(blob, noff, dev))
1334 return; /* return on error */
1337 /* Jump to next flash node */
1338 noff = fdt_node_offset_by_compatible(blob, noff,
1345 void fdt_del_node_and_alias(void *blob, const char *alias)
1347 int off = fdt_path_offset(blob, alias);
1352 fdt_del_node(blob, off);
1354 off = fdt_path_offset(blob, "/aliases");
1355 fdt_delprop(blob, off, alias);
1358 /* Helper to read a big number; size is in cells (not bytes) */
1359 static inline u64 of_read_number(const __be32 *cell, int size)
1363 r = (r << 32) | be32_to_cpu(*(cell++));
1367 #define PRu64 "%llx"
1369 /* Max address size we deal with */
1370 #define OF_MAX_ADDR_CELLS 4
1371 #define OF_BAD_ADDR ((u64)-1)
1372 #define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
1377 static void of_dump_addr(const char *s, const u32 *addr, int na)
1381 printf(" %08x", *(addr++));
1385 static void of_dump_addr(const char *s, const u32 *addr, int na) { }
1388 /* Callbacks for bus specific translators */
1391 const char *addresses;
1392 void (*count_cells)(void *blob, int parentoffset,
1393 int *addrc, int *sizec);
1394 u64 (*map)(u32 *addr, const u32 *range,
1395 int na, int ns, int pna);
1396 int (*translate)(u32 *addr, u64 offset, int na);
1399 /* Default translator (generic bus) */
1400 static void of_bus_default_count_cells(void *blob, int parentoffset,
1401 int *addrc, int *sizec)
1406 prop = fdt_getprop(blob, parentoffset, "#address-cells", NULL);
1408 *addrc = be32_to_cpup((u32 *)prop);
1414 prop = fdt_getprop(blob, parentoffset, "#size-cells", NULL);
1416 *sizec = be32_to_cpup((u32 *)prop);
1422 static u64 of_bus_default_map(u32 *addr, const u32 *range,
1423 int na, int ns, int pna)
1427 cp = of_read_number(range, na);
1428 s = of_read_number(range + na + pna, ns);
1429 da = of_read_number(addr, na);
1431 debug("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n",
1434 if (da < cp || da >= (cp + s))
1439 static int of_bus_default_translate(u32 *addr, u64 offset, int na)
1441 u64 a = of_read_number(addr, na);
1442 memset(addr, 0, na * 4);
1445 addr[na - 2] = a >> 32;
1446 addr[na - 1] = a & 0xffffffffu;
1451 /* Array of bus specific translators */
1452 static struct of_bus of_busses[] = {
1457 .count_cells = of_bus_default_count_cells,
1458 .map = of_bus_default_map,
1459 .translate = of_bus_default_translate,
1463 static int of_translate_one(void * blob, int parent, struct of_bus *bus,
1464 struct of_bus *pbus, u32 *addr,
1465 int na, int ns, int pna, const char *rprop)
1470 u64 offset = OF_BAD_ADDR;
1472 /* Normally, an absence of a "ranges" property means we are
1473 * crossing a non-translatable boundary, and thus the addresses
1474 * below the current not cannot be converted to CPU physical ones.
1475 * Unfortunately, while this is very clear in the spec, it's not
1476 * what Apple understood, and they do have things like /uni-n or
1477 * /ht nodes with no "ranges" property and a lot of perfectly
1478 * useable mapped devices below them. Thus we treat the absence of
1479 * "ranges" as equivalent to an empty "ranges" property which means
1480 * a 1:1 translation at that level. It's up to the caller not to try
1481 * to translate addresses that aren't supposed to be translated in
1482 * the first place. --BenH.
1484 ranges = (u32 *)fdt_getprop(blob, parent, rprop, &rlen);
1485 if (ranges == NULL || rlen == 0) {
1486 offset = of_read_number(addr, na);
1487 memset(addr, 0, pna * 4);
1488 debug("OF: no ranges, 1:1 translation\n");
1492 debug("OF: walking ranges...\n");
1494 /* Now walk through the ranges */
1496 rone = na + pna + ns;
1497 for (; rlen >= rone; rlen -= rone, ranges += rone) {
1498 offset = bus->map(addr, ranges, na, ns, pna);
1499 if (offset != OF_BAD_ADDR)
1502 if (offset == OF_BAD_ADDR) {
1503 debug("OF: not found !\n");
1506 memcpy(addr, ranges + na, 4 * pna);
1509 of_dump_addr("OF: parent translation for:", addr, pna);
1510 debug("OF: with offset: "PRu64"\n", offset);
1512 /* Translate it into parent bus space */
1513 return pbus->translate(addr, offset, pna);
1517 * Translate an address from the device-tree into a CPU physical address,
1518 * this walks up the tree and applies the various bus mappings on the
1521 * Note: We consider that crossing any level with #size-cells == 0 to mean
1522 * that translation is impossible (that is we are not dealing with a value
1523 * that can be mapped to a cpu physical address). This is not really specified
1524 * that way, but this is traditionally the way IBM at least do things
1526 u64 __of_translate_address(void *blob, int node_offset, const u32 *in_addr,
1530 struct of_bus *bus, *pbus;
1531 u32 addr[OF_MAX_ADDR_CELLS];
1532 int na, ns, pna, pns;
1533 u64 result = OF_BAD_ADDR;
1535 debug("OF: ** translation for device %s **\n",
1536 fdt_get_name(blob, node_offset, NULL));
1538 /* Get parent & match bus type */
1539 parent = fdt_parent_offset(blob, node_offset);
1542 bus = &of_busses[0];
1544 /* Cound address cells & copy address locally */
1545 bus->count_cells(blob, parent, &na, &ns);
1546 if (!OF_CHECK_COUNTS(na, ns)) {
1547 printf("%s: Bad cell count for %s\n", __FUNCTION__,
1548 fdt_get_name(blob, node_offset, NULL));
1551 memcpy(addr, in_addr, na * 4);
1553 debug("OF: bus is %s (na=%d, ns=%d) on %s\n",
1554 bus->name, na, ns, fdt_get_name(blob, parent, NULL));
1555 of_dump_addr("OF: translating address:", addr, na);
1559 /* Switch to parent bus */
1560 node_offset = parent;
1561 parent = fdt_parent_offset(blob, node_offset);
1563 /* If root, we have finished */
1565 debug("OF: reached root node\n");
1566 result = of_read_number(addr, na);
1570 /* Get new parent bus and counts */
1571 pbus = &of_busses[0];
1572 pbus->count_cells(blob, parent, &pna, &pns);
1573 if (!OF_CHECK_COUNTS(pna, pns)) {
1574 printf("%s: Bad cell count for %s\n", __FUNCTION__,
1575 fdt_get_name(blob, node_offset, NULL));
1579 debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
1580 pbus->name, pna, pns, fdt_get_name(blob, parent, NULL));
1582 /* Apply bus translation */
1583 if (of_translate_one(blob, node_offset, bus, pbus,
1584 addr, na, ns, pna, rprop))
1587 /* Complete the move up one level */
1592 of_dump_addr("OF: one level translation:", addr, na);
1599 u64 fdt_translate_address(void *blob, int node_offset, const u32 *in_addr)
1601 return __of_translate_address(blob, node_offset, in_addr, "ranges");
1605 * fdt_node_offset_by_compat_reg: Find a node that matches compatiable and
1606 * who's reg property matches a physical cpu address
1608 * @blob: ptr to device tree
1609 * @compat: compatiable string to match
1610 * @compat_off: property name
1613 int fdt_node_offset_by_compat_reg(void *blob, const char *compat,
1614 phys_addr_t compat_off)
1616 int len, off = fdt_node_offset_by_compatible(blob, -1, compat);
1617 while (off != -FDT_ERR_NOTFOUND) {
1618 u32 *reg = (u32 *)fdt_getprop(blob, off, "reg", &len);
1620 if (compat_off == fdt_translate_address(blob, off, reg))
1623 off = fdt_node_offset_by_compatible(blob, off, compat);
1626 return -FDT_ERR_NOTFOUND;
1630 * fdt_alloc_phandle: Return next free phandle value
1632 * @blob: ptr to device tree
1634 int fdt_alloc_phandle(void *blob)
1636 int offset, len, phandle = 0;
1639 for (offset = fdt_next_node(blob, -1, NULL); offset >= 0;
1640 offset = fdt_next_node(blob, offset, NULL)) {
1641 val = fdt_getprop(blob, offset, "linux,phandle", &len);
1643 phandle = max(*val, phandle);
1649 #if defined(CONFIG_VIDEO)
1650 int fdt_add_edid(void *blob, const char *compat, unsigned char *edid_buf)
1655 noff = fdt_node_offset_by_compatible(blob, -1, compat);
1656 if (noff != -FDT_ERR_NOTFOUND) {
1657 debug("%s: %s\n", fdt_get_name(blob, noff, 0), compat);
1659 ret = fdt_setprop(blob, noff, "edid", edid_buf, 128);
1660 if (ret == -FDT_ERR_NOSPACE) {
1661 ret = fdt_increase_size(blob, 512);
1666 } else if (ret < 0) {
1667 printf("Can't add property: %s\n", fdt_strerror(ret));
1673 printf("Can't increase blob size: %s\n", fdt_strerror(ret));
1678 void fdt_debug_print_prop(void *fdt, const char *node_path, const char *name)
1687 printf("fdt addr: 0x%x\n", fdt);
1689 err = fdt_check_header(fdt);
1691 printf("not found fdt header: %s\n", fdt_strerror(err));
1695 nodeoffset = fdt_path_offset (fdt, node_path);
1697 if (nodeoffset < 0) {
1698 printf("not found %s path\n", node_path);
1702 path = fdt_getprop(fdt, nodeoffset, name, &len);
1705 printf("not found %s prop\n", name);
1709 printf("================\n");
1710 printf("%s/%s: ", node_path, name);
1711 for (i = 0; i < len; i++) {
1712 printf("%c", *(path)++);
1715 printf("================\n");