~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/u-boot/common/fdt_support.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * (C) Copyright 2007
 
3
 * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
 
4
 *
 
5
 * Copyright 2010-2011 Freescale Semiconductor, Inc.
 
6
 *
 
7
 * SPDX-License-Identifier:     GPL-2.0+
 
8
 */
 
9
 
 
10
#include <common.h>
 
11
#include <stdio_dev.h>
 
12
#include <linux/ctype.h>
 
13
#include <linux/types.h>
 
14
#include <asm/global_data.h>
 
15
#include <libfdt.h>
 
16
#include <fdt_support.h>
 
17
#include <exports.h>
 
18
 
 
19
/*
 
20
 * Global data (for the gd->bd)
 
21
 */
 
22
DECLARE_GLOBAL_DATA_PTR;
 
23
 
 
24
/*
 
25
 * Get cells len in bytes
 
26
 *     if #NNNN-cells property is 2 then len is 8
 
27
 *     otherwise len is 4
 
28
 */
 
29
static int get_cells_len(void *blob, char *nr_cells_name)
 
30
{
 
31
        const fdt32_t *cell;
 
32
 
 
33
        cell = fdt_getprop(blob, 0, nr_cells_name, NULL);
 
34
        if (cell && fdt32_to_cpu(*cell) == 2)
 
35
                return 8;
 
36
 
 
37
        return 4;
 
38
}
 
39
 
 
40
/*
 
41
 * Write a 4 or 8 byte big endian cell
 
42
 */
 
43
static void write_cell(u8 *addr, u64 val, int size)
 
44
{
 
45
        int shift = (size - 1) * 8;
 
46
        while (size-- > 0) {
 
47
                *addr++ = (val >> shift) & 0xff;
 
48
                shift -= 8;
 
49
        }
 
50
}
 
51
 
 
52
/**
 
53
 * fdt_getprop_u32_default_node - Return a node's property or a default
 
54
 *
 
55
 * @fdt: ptr to device tree
 
56
 * @off: offset of node
 
57
 * @cell: cell offset in property
 
58
 * @prop: property name
 
59
 * @dflt: default value if the property isn't found
 
60
 *
 
61
 * Convenience function to return a node's property or a default value if
 
62
 * the property doesn't exist.
 
63
 */
 
64
u32 fdt_getprop_u32_default_node(const void *fdt, int off, int cell,
 
65
                                const char *prop, const u32 dflt)
 
66
{
 
67
        const fdt32_t *val;
 
68
        int len;
 
69
 
 
70
        val = fdt_getprop(fdt, off, prop, &len);
 
71
 
 
72
        /* Check if property exists */
 
73
        if (!val)
 
74
                return dflt;
 
75
 
 
76
        /* Check if property is long enough */
 
77
        if (len < ((cell + 1) * sizeof(uint32_t)))
 
78
                return dflt;
 
79
 
 
80
        return fdt32_to_cpu(*val);
 
81
}
 
82
 
 
83
/**
 
84
 * fdt_getprop_u32_default - Find a node and return it's property or a default
 
85
 *
 
86
 * @fdt: ptr to device tree
 
87
 * @path: path of node
 
88
 * @prop: property name
 
89
 * @dflt: default value if the property isn't found
 
90
 *
 
91
 * Convenience function to find a node and return it's property or a
 
92
 * default value if it doesn't exist.
 
93
 */
 
94
u32 fdt_getprop_u32_default(const void *fdt, const char *path,
 
95
                                const char *prop, const u32 dflt)
 
96
{
 
97
        int off;
 
98
 
 
99
        off = fdt_path_offset(fdt, path);
 
100
        if (off < 0)
 
101
                return dflt;
 
102
 
 
103
        return fdt_getprop_u32_default_node(fdt, off, 0, prop, dflt);
 
104
}
 
105
 
 
106
/**
 
107
 * fdt_find_and_setprop: Find a node and set it's property
 
108
 *
 
109
 * @fdt: ptr to device tree
 
110
 * @node: path of node
 
111
 * @prop: property name
 
112
 * @val: ptr to new value
 
113
 * @len: length of new property value
 
114
 * @create: flag to create the property if it doesn't exist
 
115
 *
 
116
 * Convenience function to directly set a property given the path to the node.
 
117
 */
 
118
int fdt_find_and_setprop(void *fdt, const char *node, const char *prop,
 
119
                         const void *val, int len, int create)
 
120
{
 
121
        int nodeoff = fdt_path_offset(fdt, node);
 
122
 
 
123
        if (nodeoff < 0)
 
124
                return nodeoff;
 
125
 
 
126
        if ((!create) && (fdt_get_property(fdt, nodeoff, prop, NULL) == NULL))
 
127
                return 0; /* create flag not set; so exit quietly */
 
128
 
 
129
        return fdt_setprop(fdt, nodeoff, prop, val, len);
 
130
}
 
131
 
 
132
#ifdef CONFIG_OF_STDOUT_VIA_ALIAS
 
133
 
 
134
#ifdef CONFIG_CONS_INDEX
 
135
static void fdt_fill_multisername(char *sername, size_t maxlen)
 
136
{
 
137
        const char *outname = stdio_devices[stdout]->name;
 
138
 
 
139
        if (strcmp(outname, "serial") > 0)
 
140
                strncpy(sername, outname, maxlen);
 
141
 
 
142
        /* eserial? */
 
143
        if (strcmp(outname + 1, "serial") > 0)
 
144
                strncpy(sername, outname + 1, maxlen);
 
145
}
 
146
#endif
 
147
 
 
148
static int fdt_fixup_stdout(void *fdt, int chosenoff)
 
149
{
 
150
        int err = 0;
 
151
#ifdef CONFIG_CONS_INDEX
 
152
        int node;
 
153
        char sername[9] = { 0 };
 
154
        const char *path;
 
155
 
 
156
        fdt_fill_multisername(sername, sizeof(sername) - 1);
 
157
        if (!sername[0])
 
158
                sprintf(sername, "serial%d", CONFIG_CONS_INDEX - 1);
 
159
 
 
160
        err = node = fdt_path_offset(fdt, "/aliases");
 
161
        if (node >= 0) {
 
162
                int len;
 
163
                path = fdt_getprop(fdt, node, sername, &len);
 
164
                if (path) {
 
165
                        char *p = malloc(len);
 
166
                        err = -FDT_ERR_NOSPACE;
 
167
                        if (p) {
 
168
                                memcpy(p, path, len);
 
169
                                err = fdt_setprop(fdt, chosenoff,
 
170
                                        "linux,stdout-path", p, len);
 
171
                                free(p);
 
172
                        }
 
173
                } else {
 
174
                        err = len;
 
175
                }
 
176
        }
 
177
#endif
 
178
        if (err < 0)
 
179
                printf("WARNING: could not set linux,stdout-path %s.\n",
 
180
                                fdt_strerror(err));
 
181
 
 
182
        return err;
 
183
}
 
184
#endif
 
185
 
 
186
int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end, int force)
 
187
{
 
188
        int   nodeoffset, addr_cell_len;
 
189
        int   err, j, total;
 
190
        fdt64_t  tmp;
 
191
        const char *path;
 
192
        uint64_t addr, size;
 
193
 
 
194
        /* Find the "chosen" node.  */
 
195
        nodeoffset = fdt_path_offset (fdt, "/chosen");
 
196
 
 
197
        /* If there is no "chosen" node in the blob return */
 
198
        if (nodeoffset < 0) {
 
199
                printf("fdt_initrd: %s\n", fdt_strerror(nodeoffset));
 
200
                return nodeoffset;
 
201
        }
 
202
 
 
203
        /* just return if initrd_start/end aren't valid */
 
204
        if ((initrd_start == 0) || (initrd_end == 0))
 
205
                return 0;
 
206
 
 
207
        total = fdt_num_mem_rsv(fdt);
 
208
 
 
209
        /*
 
210
         * Look for an existing entry and update it.  If we don't find
 
211
         * the entry, we will j be the next available slot.
 
212
         */
 
213
        for (j = 0; j < total; j++) {
 
214
                err = fdt_get_mem_rsv(fdt, j, &addr, &size);
 
215
                if (addr == initrd_start) {
 
216
                        fdt_del_mem_rsv(fdt, j);
 
217
                        break;
 
218
                }
 
219
        }
 
220
 
 
221
        err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start);
 
222
        if (err < 0) {
 
223
                printf("fdt_initrd: %s\n", fdt_strerror(err));
 
224
                return err;
 
225
        }
 
226
 
 
227
        addr_cell_len = get_cells_len(fdt, "#address-cells");
 
228
 
 
229
        path = fdt_getprop(fdt, nodeoffset, "linux,initrd-start", NULL);
 
230
        if ((path == NULL) || force) {
 
231
                write_cell((u8 *)&tmp, initrd_start, addr_cell_len);
 
232
                err = fdt_setprop(fdt, nodeoffset,
 
233
                        "linux,initrd-start", &tmp, addr_cell_len);
 
234
                if (err < 0) {
 
235
                        printf("WARNING: "
 
236
                                "could not set linux,initrd-start %s.\n",
 
237
                                fdt_strerror(err));
 
238
                        return err;
 
239
                }
 
240
                write_cell((u8 *)&tmp, initrd_end, addr_cell_len);
 
241
                err = fdt_setprop(fdt, nodeoffset,
 
242
                        "linux,initrd-end", &tmp, addr_cell_len);
 
243
                if (err < 0) {
 
244
                        printf("WARNING: could not set linux,initrd-end %s.\n",
 
245
                                fdt_strerror(err));
 
246
 
 
247
                        return err;
 
248
                }
 
249
        }
 
250
 
 
251
        return 0;
 
252
}
 
253
 
 
254
int fdt_chosen(void *fdt, int force)
 
255
{
 
256
        int   nodeoffset;
 
257
        int   err;
 
258
        char  *str;             /* used to set string properties */
 
259
        const char *path;
 
260
 
 
261
        err = fdt_check_header(fdt);
 
262
        if (err < 0) {
 
263
                printf("fdt_chosen: %s\n", fdt_strerror(err));
 
264
                return err;
 
265
        }
 
266
 
 
267
        /*
 
268
         * Find the "chosen" node.
 
269
         */
 
270
        nodeoffset = fdt_path_offset (fdt, "/chosen");
 
271
 
 
272
        /*
 
273
         * If there is no "chosen" node in the blob, create it.
 
274
         */
 
275
        if (nodeoffset < 0) {
 
276
                /*
 
277
                 * Create a new node "/chosen" (offset 0 is root level)
 
278
                 */
 
279
                nodeoffset = fdt_add_subnode(fdt, 0, "chosen");
 
280
                if (nodeoffset < 0) {
 
281
                        printf("WARNING: could not create /chosen %s.\n",
 
282
                                fdt_strerror(nodeoffset));
 
283
                        return nodeoffset;
 
284
                }
 
285
        }
 
286
 
 
287
        /*
 
288
         * Create /chosen properites that don't exist in the fdt.
 
289
         * If the property exists, update it only if the "force" parameter
 
290
         * is true.
 
291
         */
 
292
        str = getenv("bootargs");
 
293
        if (str != NULL) {
 
294
                path = fdt_getprop(fdt, nodeoffset, "bootargs", NULL);
 
295
                if ((path == NULL) || force) {
 
296
                        err = fdt_setprop(fdt, nodeoffset,
 
297
                                "bootargs", str, strlen(str)+1);
 
298
                        if (err < 0)
 
299
                                printf("WARNING: could not set bootargs %s.\n",
 
300
                                        fdt_strerror(err));
 
301
                }
 
302
        }
 
303
 
 
304
#ifdef CONFIG_OF_STDOUT_VIA_ALIAS
 
305
        path = fdt_getprop(fdt, nodeoffset, "linux,stdout-path", NULL);
 
306
        if ((path == NULL) || force)
 
307
                err = fdt_fixup_stdout(fdt, nodeoffset);
 
308
#endif
 
309
 
 
310
#ifdef OF_STDOUT_PATH
 
311
        path = fdt_getprop(fdt, nodeoffset, "linux,stdout-path", NULL);
 
312
        if ((path == NULL) || force) {
 
313
                err = fdt_setprop(fdt, nodeoffset,
 
314
                        "linux,stdout-path", OF_STDOUT_PATH, strlen(OF_STDOUT_PATH)+1);
 
315
                if (err < 0)
 
316
                        printf("WARNING: could not set linux,stdout-path %s.\n",
 
317
                                fdt_strerror(err));
 
318
        }
 
319
#endif
 
320
 
 
321
        return err;
 
322
}
 
323
 
 
324
void do_fixup_by_path(void *fdt, const char *path, const char *prop,
 
325
                      const void *val, int len, int create)
 
326
{
 
327
#if defined(DEBUG)
 
328
        int i;
 
329
        debug("Updating property '%s/%s' = ", path, prop);
 
330
        for (i = 0; i < len; i++)
 
331
                debug(" %.2x", *(u8*)(val+i));
 
332
        debug("\n");
 
333
#endif
 
334
        int rc = fdt_find_and_setprop(fdt, path, prop, val, len, create);
 
335
        if (rc)
 
336
                printf("Unable to update property %s:%s, err=%s\n",
 
337
                        path, prop, fdt_strerror(rc));
 
338
}
 
339
 
 
340
void do_fixup_by_path_u32(void *fdt, const char *path, const char *prop,
 
341
                          u32 val, int create)
 
342
{
 
343
        fdt32_t tmp = cpu_to_fdt32(val);
 
344
        do_fixup_by_path(fdt, path, prop, &tmp, sizeof(tmp), create);
 
345
}
 
346
 
 
347
void do_fixup_by_prop(void *fdt,
 
348
                      const char *pname, const void *pval, int plen,
 
349
                      const char *prop, const void *val, int len,
 
350
                      int create)
 
351
{
 
352
        int off;
 
353
#if defined(DEBUG)
 
354
        int i;
 
355
        debug("Updating property '%s' = ", prop);
 
356
        for (i = 0; i < len; i++)
 
357
                debug(" %.2x", *(u8*)(val+i));
 
358
        debug("\n");
 
359
#endif
 
360
        off = fdt_node_offset_by_prop_value(fdt, -1, pname, pval, plen);
 
361
        while (off != -FDT_ERR_NOTFOUND) {
 
362
                if (create || (fdt_get_property(fdt, off, prop, NULL) != NULL))
 
363
                        fdt_setprop(fdt, off, prop, val, len);
 
364
                off = fdt_node_offset_by_prop_value(fdt, off, pname, pval, plen);
 
365
        }
 
366
}
 
367
 
 
368
void do_fixup_by_prop_u32(void *fdt,
 
369
                          const char *pname, const void *pval, int plen,
 
370
                          const char *prop, u32 val, int create)
 
371
{
 
372
        fdt32_t tmp = cpu_to_fdt32(val);
 
373
        do_fixup_by_prop(fdt, pname, pval, plen, prop, &tmp, 4, create);
 
374
}
 
375
 
 
376
void do_fixup_by_compat(void *fdt, const char *compat,
 
377
                        const char *prop, const void *val, int len, int create)
 
378
{
 
379
        int off = -1;
 
380
#if defined(DEBUG)
 
381
        int i;
 
382
        debug("Updating property '%s' = ", prop);
 
383
        for (i = 0; i < len; i++)
 
384
                debug(" %.2x", *(u8*)(val+i));
 
385
        debug("\n");
 
386
#endif
 
387
        off = fdt_node_offset_by_compatible(fdt, -1, compat);
 
388
        while (off != -FDT_ERR_NOTFOUND) {
 
389
                if (create || (fdt_get_property(fdt, off, prop, NULL) != NULL))
 
390
                        fdt_setprop(fdt, off, prop, val, len);
 
391
                off = fdt_node_offset_by_compatible(fdt, off, compat);
 
392
        }
 
393
}
 
394
 
 
395
void do_fixup_by_compat_u32(void *fdt, const char *compat,
 
396
                            const char *prop, u32 val, int create)
 
397
{
 
398
        fdt32_t tmp = cpu_to_fdt32(val);
 
399
        do_fixup_by_compat(fdt, compat, prop, &tmp, 4, create);
 
400
}
 
401
 
 
402
#ifdef CONFIG_NR_DRAM_BANKS
 
403
#define MEMORY_BANKS_MAX CONFIG_NR_DRAM_BANKS
 
404
#else
 
405
#define MEMORY_BANKS_MAX 4
 
406
#endif
 
407
int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[], int banks)
 
408
{
 
409
        int err, nodeoffset;
 
410
        int addr_cell_len, size_cell_len, len;
 
411
        u8 tmp[MEMORY_BANKS_MAX * 16]; /* Up to 64-bit address + 64-bit size */
 
412
        int bank;
 
413
 
 
414
        if (banks > MEMORY_BANKS_MAX) {
 
415
                printf("%s: num banks %d exceeds hardcoded limit %d."
 
416
                       " Recompile with higher MEMORY_BANKS_MAX?\n",
 
417
                       __FUNCTION__, banks, MEMORY_BANKS_MAX);
 
418
                return -1;
 
419
        }
 
420
 
 
421
        err = fdt_check_header(blob);
 
422
        if (err < 0) {
 
423
                printf("%s: %s\n", __FUNCTION__, fdt_strerror(err));
 
424
                return err;
 
425
        }
 
426
 
 
427
        /* update, or add and update /memory node */
 
428
        nodeoffset = fdt_path_offset(blob, "/memory");
 
429
        if (nodeoffset < 0) {
 
430
                nodeoffset = fdt_add_subnode(blob, 0, "memory");
 
431
                if (nodeoffset < 0) {
 
432
                        printf("WARNING: could not create /memory: %s.\n",
 
433
                                        fdt_strerror(nodeoffset));
 
434
                        return nodeoffset;
 
435
                }
 
436
        }
 
437
        err = fdt_setprop(blob, nodeoffset, "device_type", "memory",
 
438
                        sizeof("memory"));
 
439
        if (err < 0) {
 
440
                printf("WARNING: could not set %s %s.\n", "device_type",
 
441
                                fdt_strerror(err));
 
442
                return err;
 
443
        }
 
444
 
 
445
        addr_cell_len = get_cells_len(blob, "#address-cells");
 
446
        size_cell_len = get_cells_len(blob, "#size-cells");
 
447
 
 
448
        for (bank = 0, len = 0; bank < banks; bank++) {
 
449
                write_cell(tmp + len, start[bank], addr_cell_len);
 
450
                len += addr_cell_len;
 
451
 
 
452
                write_cell(tmp + len, size[bank], size_cell_len);
 
453
                len += size_cell_len;
 
454
        }
 
455
 
 
456
        err = fdt_setprop(blob, nodeoffset, "reg", tmp, len);
 
457
        if (err < 0) {
 
458
                printf("WARNING: could not set %s %s.\n",
 
459
                                "reg", fdt_strerror(err));
 
460
                return err;
 
461
        }
 
462
        return 0;
 
463
}
 
464
 
 
465
int fdt_fixup_memory(void *blob, u64 start, u64 size)
 
466
{
 
467
        return fdt_fixup_memory_banks(blob, &start, &size, 1);
 
468
}
 
469
 
 
470
void fdt_fixup_ethernet(void *fdt)
 
471
{
 
472
        int node, i, j;
 
473
        char enet[16], *tmp, *end;
 
474
        char mac[16];
 
475
        const char *path;
 
476
        unsigned char mac_addr[6];
 
477
 
 
478
        node = fdt_path_offset(fdt, "/aliases");
 
479
        if (node < 0)
 
480
                return;
 
481
 
 
482
        i = 0;
 
483
        strcpy(mac, "ethaddr");
 
484
        while ((tmp = getenv(mac)) != NULL) {
 
485
                sprintf(enet, "ethernet%d", i);
 
486
                path = fdt_getprop(fdt, node, enet, NULL);
 
487
                if (!path) {
 
488
                        debug("No alias for %s\n", enet);
 
489
                        sprintf(mac, "eth%daddr", ++i);
 
490
                        continue;
 
491
                }
 
492
 
 
493
                for (j = 0; j < 6; j++) {
 
494
                        mac_addr[j] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
 
495
                        if (tmp)
 
496
                                tmp = (*end) ? end+1 : end;
 
497
                }
 
498
 
 
499
                do_fixup_by_path(fdt, path, "mac-address", &mac_addr, 6, 0);
 
500
                do_fixup_by_path(fdt, path, "local-mac-address",
 
501
                                &mac_addr, 6, 1);
 
502
 
 
503
                sprintf(mac, "eth%daddr", ++i);
 
504
        }
 
505
}
 
506
 
 
507
/* Resize the fdt to its actual size + a bit of padding */
 
508
int fdt_resize(void *blob)
 
509
{
 
510
        int i;
 
511
        uint64_t addr, size;
 
512
        int total, ret;
 
513
        uint actualsize;
 
514
 
 
515
        if (!blob)
 
516
                return 0;
 
517
 
 
518
        total = fdt_num_mem_rsv(blob);
 
519
        for (i = 0; i < total; i++) {
 
520
                fdt_get_mem_rsv(blob, i, &addr, &size);
 
521
                if (addr == (uintptr_t)blob) {
 
522
                        fdt_del_mem_rsv(blob, i);
 
523
                        break;
 
524
                }
 
525
        }
 
526
 
 
527
        /*
 
528
         * Calculate the actual size of the fdt
 
529
         * plus the size needed for 5 fdt_add_mem_rsv, one
 
530
         * for the fdt itself and 4 for a possible initrd
 
531
         * ((initrd-start + initrd-end) * 2 (name & value))
 
532
         */
 
533
        actualsize = fdt_off_dt_strings(blob) +
 
534
                fdt_size_dt_strings(blob) + 5 * sizeof(struct fdt_reserve_entry);
 
535
 
 
536
        /* Make it so the fdt ends on a page boundary */
 
537
        actualsize = ALIGN(actualsize + ((uintptr_t)blob & 0xfff), 0x1000);
 
538
        actualsize = actualsize - ((uintptr_t)blob & 0xfff);
 
539
 
 
540
        /* Change the fdt header to reflect the correct size */
 
541
        fdt_set_totalsize(blob, actualsize);
 
542
 
 
543
        /* Add the new reservation */
 
544
        ret = fdt_add_mem_rsv(blob, (uintptr_t)blob, actualsize);
 
545
        if (ret < 0)
 
546
                return ret;
 
547
 
 
548
        return actualsize;
 
549
}
 
550
 
 
551
#ifdef CONFIG_PCI
 
552
#define CONFIG_SYS_PCI_NR_INBOUND_WIN 4
 
553
 
 
554
#define FDT_PCI_PREFETCH        (0x40000000)
 
555
#define FDT_PCI_MEM32           (0x02000000)
 
556
#define FDT_PCI_IO              (0x01000000)
 
557
#define FDT_PCI_MEM64           (0x03000000)
 
558
 
 
559
int fdt_pci_dma_ranges(void *blob, int phb_off, struct pci_controller *hose) {
 
560
 
 
561
        int addrcell, sizecell, len, r;
 
562
        u32 *dma_range;
 
563
        /* sized based on pci addr cells, size-cells, & address-cells */
 
564
        u32 dma_ranges[(3 + 2 + 2) * CONFIG_SYS_PCI_NR_INBOUND_WIN];
 
565
 
 
566
        addrcell = fdt_getprop_u32_default(blob, "/", "#address-cells", 1);
 
567
        sizecell = fdt_getprop_u32_default(blob, "/", "#size-cells", 1);
 
568
 
 
569
        dma_range = &dma_ranges[0];
 
570
        for (r = 0; r < hose->region_count; r++) {
 
571
                u64 bus_start, phys_start, size;
 
572
 
 
573
                /* skip if !PCI_REGION_SYS_MEMORY */
 
574
                if (!(hose->regions[r].flags & PCI_REGION_SYS_MEMORY))
 
575
                        continue;
 
576
 
 
577
                bus_start = (u64)hose->regions[r].bus_start;
 
578
                phys_start = (u64)hose->regions[r].phys_start;
 
579
                size = (u64)hose->regions[r].size;
 
580
 
 
581
                dma_range[0] = 0;
 
582
                if (size >= 0x100000000ull)
 
583
                        dma_range[0] |= FDT_PCI_MEM64;
 
584
                else
 
585
                        dma_range[0] |= FDT_PCI_MEM32;
 
586
                if (hose->regions[r].flags & PCI_REGION_PREFETCH)
 
587
                        dma_range[0] |= FDT_PCI_PREFETCH;
 
588
#ifdef CONFIG_SYS_PCI_64BIT
 
589
                dma_range[1] = bus_start >> 32;
 
590
#else
 
591
                dma_range[1] = 0;
 
592
#endif
 
593
                dma_range[2] = bus_start & 0xffffffff;
 
594
 
 
595
                if (addrcell == 2) {
 
596
                        dma_range[3] = phys_start >> 32;
 
597
                        dma_range[4] = phys_start & 0xffffffff;
 
598
                } else {
 
599
                        dma_range[3] = phys_start & 0xffffffff;
 
600
                }
 
601
 
 
602
                if (sizecell == 2) {
 
603
                        dma_range[3 + addrcell + 0] = size >> 32;
 
604
                        dma_range[3 + addrcell + 1] = size & 0xffffffff;
 
605
                } else {
 
606
                        dma_range[3 + addrcell + 0] = size & 0xffffffff;
 
607
                }
 
608
 
 
609
                dma_range += (3 + addrcell + sizecell);
 
610
        }
 
611
 
 
612
        len = dma_range - &dma_ranges[0];
 
613
        if (len)
 
614
                fdt_setprop(blob, phb_off, "dma-ranges", &dma_ranges[0], len*4);
 
615
 
 
616
        return 0;
 
617
}
 
618
#endif
 
619
 
 
620
#ifdef CONFIG_FDT_FIXUP_NOR_FLASH_SIZE
 
621
/*
 
622
 * Provide a weak default function to return the flash bank size.
 
623
 * There might be multiple non-identical flash chips connected to one
 
624
 * chip-select, so we need to pass an index as well.
 
625
 */
 
626
u32 __flash_get_bank_size(int cs, int idx)
 
627
{
 
628
        extern flash_info_t flash_info[];
 
629
 
 
630
        /*
 
631
         * As default, a simple 1:1 mapping is provided. Boards with
 
632
         * a different mapping need to supply a board specific mapping
 
633
         * routine.
 
634
         */
 
635
        return flash_info[cs].size;
 
636
}
 
637
u32 flash_get_bank_size(int cs, int idx)
 
638
        __attribute__((weak, alias("__flash_get_bank_size")));
 
639
 
 
640
/*
 
641
 * This function can be used to update the size in the "reg" property
 
642
 * of all NOR FLASH device nodes. This is necessary for boards with
 
643
 * non-fixed NOR FLASH sizes.
 
644
 */
 
645
int fdt_fixup_nor_flash_size(void *blob)
 
646
{
 
647
        char compat[][16] = { "cfi-flash", "jedec-flash" };
 
648
        int off;
 
649
        int len;
 
650
        struct fdt_property *prop;
 
651
        u32 *reg, *reg2;
 
652
        int i;
 
653
 
 
654
        for (i = 0; i < 2; i++) {
 
655
                off = fdt_node_offset_by_compatible(blob, -1, compat[i]);
 
656
                while (off != -FDT_ERR_NOTFOUND) {
 
657
                        int idx;
 
658
 
 
659
                        /*
 
660
                         * Found one compatible node, so fixup the size
 
661
                         * int its reg properties
 
662
                         */
 
663
                        prop = fdt_get_property_w(blob, off, "reg", &len);
 
664
                        if (prop) {
 
665
                                int tuple_size = 3 * sizeof(reg);
 
666
 
 
667
                                /*
 
668
                                 * There might be multiple reg-tuples,
 
669
                                 * so loop through them all
 
670
                                 */
 
671
                                reg = reg2 = (u32 *)&prop->data[0];
 
672
                                for (idx = 0; idx < (len / tuple_size); idx++) {
 
673
                                        /*
 
674
                                         * Update size in reg property
 
675
                                         */
 
676
                                        reg[2] = flash_get_bank_size(reg[0],
 
677
                                                                     idx);
 
678
 
 
679
                                        /*
 
680
                                         * Point to next reg tuple
 
681
                                         */
 
682
                                        reg += 3;
 
683
                                }
 
684
 
 
685
                                fdt_setprop(blob, off, "reg", reg2, len);
 
686
                        }
 
687
 
 
688
                        /* Move to next compatible node */
 
689
                        off = fdt_node_offset_by_compatible(blob, off,
 
690
                                                            compat[i]);
 
691
                }
 
692
        }
 
693
 
 
694
        return 0;
 
695
}
 
696
#endif
 
697
 
 
698
int fdt_increase_size(void *fdt, int add_len)
 
699
{
 
700
        int newlen;
 
701
 
 
702
        newlen = fdt_totalsize(fdt) + add_len;
 
703
 
 
704
        /* Open in place with a new len */
 
705
        return fdt_open_into(fdt, fdt, newlen);
 
706
}
 
707
 
 
708
#ifdef CONFIG_FDT_FIXUP_PARTITIONS
 
709
#include <jffs2/load_kernel.h>
 
710
#include <mtd_node.h>
 
711
 
 
712
struct reg_cell {
 
713
        unsigned int r0;
 
714
        unsigned int r1;
 
715
};
 
716
 
 
717
int fdt_del_subnodes(const void *blob, int parent_offset)
 
718
{
 
719
        int off, ndepth;
 
720
        int ret;
 
721
 
 
722
        for (ndepth = 0, off = fdt_next_node(blob, parent_offset, &ndepth);
 
723
             (off >= 0) && (ndepth > 0);
 
724
             off = fdt_next_node(blob, off, &ndepth)) {
 
725
                if (ndepth == 1) {
 
726
                        debug("delete %s: offset: %x\n",
 
727
                                fdt_get_name(blob, off, 0), off);
 
728
                        ret = fdt_del_node((void *)blob, off);
 
729
                        if (ret < 0) {
 
730
                                printf("Can't delete node: %s\n",
 
731
                                        fdt_strerror(ret));
 
732
                                return ret;
 
733
                        } else {
 
734
                                ndepth = 0;
 
735
                                off = parent_offset;
 
736
                        }
 
737
                }
 
738
        }
 
739
        return 0;
 
740
}
 
741
 
 
742
int fdt_del_partitions(void *blob, int parent_offset)
 
743
{
 
744
        const void *prop;
 
745
        int ndepth = 0;
 
746
        int off;
 
747
        int ret;
 
748
 
 
749
        off = fdt_next_node(blob, parent_offset, &ndepth);
 
750
        if (off > 0 && ndepth == 1) {
 
751
                prop = fdt_getprop(blob, off, "label", NULL);
 
752
                if (prop == NULL) {
 
753
                        /*
 
754
                         * Could not find label property, nand {}; node?
 
755
                         * Check subnode, delete partitions there if any.
 
756
                         */
 
757
                        return fdt_del_partitions(blob, off);
 
758
                } else {
 
759
                        ret = fdt_del_subnodes(blob, parent_offset);
 
760
                        if (ret < 0) {
 
761
                                printf("Can't remove subnodes: %s\n",
 
762
                                        fdt_strerror(ret));
 
763
                                return ret;
 
764
                        }
 
765
                }
 
766
        }
 
767
        return 0;
 
768
}
 
769
 
 
770
int fdt_node_set_part_info(void *blob, int parent_offset,
 
771
                           struct mtd_device *dev)
 
772
{
 
773
        struct list_head *pentry;
 
774
        struct part_info *part;
 
775
        struct reg_cell cell;
 
776
        int off, ndepth = 0;
 
777
        int part_num, ret;
 
778
        char buf[64];
 
779
 
 
780
        ret = fdt_del_partitions(blob, parent_offset);
 
781
        if (ret < 0)
 
782
                return ret;
 
783
 
 
784
        /*
 
785
         * Check if it is nand {}; subnode, adjust
 
786
         * the offset in this case
 
787
         */
 
788
        off = fdt_next_node(blob, parent_offset, &ndepth);
 
789
        if (off > 0 && ndepth == 1)
 
790
                parent_offset = off;
 
791
 
 
792
        part_num = 0;
 
793
        list_for_each_prev(pentry, &dev->parts) {
 
794
                int newoff;
 
795
 
 
796
                part = list_entry(pentry, struct part_info, link);
 
797
 
 
798
                debug("%2d: %-20s0x%08llx\t0x%08llx\t%d\n",
 
799
                        part_num, part->name, part->size,
 
800
                        part->offset, part->mask_flags);
 
801
 
 
802
                sprintf(buf, "partition@%llx", part->offset);
 
803
add_sub:
 
804
                ret = fdt_add_subnode(blob, parent_offset, buf);
 
805
                if (ret == -FDT_ERR_NOSPACE) {
 
806
                        ret = fdt_increase_size(blob, 512);
 
807
                        if (!ret)
 
808
                                goto add_sub;
 
809
                        else
 
810
                                goto err_size;
 
811
                } else if (ret < 0) {
 
812
                        printf("Can't add partition node: %s\n",
 
813
                                fdt_strerror(ret));
 
814
                        return ret;
 
815
                }
 
816
                newoff = ret;
 
817
 
 
818
                /* Check MTD_WRITEABLE_CMD flag */
 
819
                if (part->mask_flags & 1) {
 
820
add_ro:
 
821
                        ret = fdt_setprop(blob, newoff, "read_only", NULL, 0);
 
822
                        if (ret == -FDT_ERR_NOSPACE) {
 
823
                                ret = fdt_increase_size(blob, 512);
 
824
                                if (!ret)
 
825
                                        goto add_ro;
 
826
                                else
 
827
                                        goto err_size;
 
828
                        } else if (ret < 0)
 
829
                                goto err_prop;
 
830
                }
 
831
 
 
832
                cell.r0 = cpu_to_fdt32(part->offset);
 
833
                cell.r1 = cpu_to_fdt32(part->size);
 
834
add_reg:
 
835
                ret = fdt_setprop(blob, newoff, "reg", &cell, sizeof(cell));
 
836
                if (ret == -FDT_ERR_NOSPACE) {
 
837
                        ret = fdt_increase_size(blob, 512);
 
838
                        if (!ret)
 
839
                                goto add_reg;
 
840
                        else
 
841
                                goto err_size;
 
842
                } else if (ret < 0)
 
843
                        goto err_prop;
 
844
 
 
845
add_label:
 
846
                ret = fdt_setprop_string(blob, newoff, "label", part->name);
 
847
                if (ret == -FDT_ERR_NOSPACE) {
 
848
                        ret = fdt_increase_size(blob, 512);
 
849
                        if (!ret)
 
850
                                goto add_label;
 
851
                        else
 
852
                                goto err_size;
 
853
                } else if (ret < 0)
 
854
                        goto err_prop;
 
855
 
 
856
                part_num++;
 
857
        }
 
858
        return 0;
 
859
err_size:
 
860
        printf("Can't increase blob size: %s\n", fdt_strerror(ret));
 
861
        return ret;
 
862
err_prop:
 
863
        printf("Can't add property: %s\n", fdt_strerror(ret));
 
864
        return ret;
 
865
}
 
866
 
 
867
/*
 
868
 * Update partitions in nor/nand nodes using info from
 
869
 * mtdparts environment variable. The nodes to update are
 
870
 * specified by node_info structure which contains mtd device
 
871
 * type and compatible string: E. g. the board code in
 
872
 * ft_board_setup() could use:
 
873
 *
 
874
 *      struct node_info nodes[] = {
 
875
 *              { "fsl,mpc5121-nfc",    MTD_DEV_TYPE_NAND, },
 
876
 *              { "cfi-flash",          MTD_DEV_TYPE_NOR,  },
 
877
 *      };
 
878
 *
 
879
 *      fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes));
 
880
 */
 
881
void fdt_fixup_mtdparts(void *blob, void *node_info, int node_info_size)
 
882
{
 
883
        struct node_info *ni = node_info;
 
884
        struct mtd_device *dev;
 
885
        char *parts;
 
886
        int i, idx;
 
887
        int noff;
 
888
 
 
889
        parts = getenv("mtdparts");
 
890
        if (!parts)
 
891
                return;
 
892
 
 
893
        if (mtdparts_init() != 0)
 
894
                return;
 
895
 
 
896
        for (i = 0; i < node_info_size; i++) {
 
897
                idx = 0;
 
898
                noff = fdt_node_offset_by_compatible(blob, -1, ni[i].compat);
 
899
                while (noff != -FDT_ERR_NOTFOUND) {
 
900
                        debug("%s: %s, mtd dev type %d\n",
 
901
                                fdt_get_name(blob, noff, 0),
 
902
                                ni[i].compat, ni[i].type);
 
903
                        dev = device_find(ni[i].type, idx++);
 
904
                        if (dev) {
 
905
                                if (fdt_node_set_part_info(blob, noff, dev))
 
906
                                        return; /* return on error */
 
907
                        }
 
908
 
 
909
                        /* Jump to next flash node */
 
910
                        noff = fdt_node_offset_by_compatible(blob, noff,
 
911
                                                             ni[i].compat);
 
912
                }
 
913
        }
 
914
}
 
915
#endif
 
916
 
 
917
void fdt_del_node_and_alias(void *blob, const char *alias)
 
918
{
 
919
        int off = fdt_path_offset(blob, alias);
 
920
 
 
921
        if (off < 0)
 
922
                return;
 
923
 
 
924
        fdt_del_node(blob, off);
 
925
 
 
926
        off = fdt_path_offset(blob, "/aliases");
 
927
        fdt_delprop(blob, off, alias);
 
928
}
 
929
 
 
930
/* Helper to read a big number; size is in cells (not bytes) */
 
931
static inline u64 of_read_number(const fdt32_t *cell, int size)
 
932
{
 
933
        u64 r = 0;
 
934
        while (size--)
 
935
                r = (r << 32) | fdt32_to_cpu(*(cell++));
 
936
        return r;
 
937
}
 
938
 
 
939
#define PRu64   "%llx"
 
940
 
 
941
/* Max address size we deal with */
 
942
#define OF_MAX_ADDR_CELLS       4
 
943
#define OF_BAD_ADDR     ((u64)-1)
 
944
#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
 
945
                        (ns) > 0)
 
946
 
 
947
/* Debug utility */
 
948
#ifdef DEBUG
 
949
static void of_dump_addr(const char *s, const fdt32_t *addr, int na)
 
950
{
 
951
        printf("%s", s);
 
952
        while(na--)
 
953
                printf(" %08x", *(addr++));
 
954
        printf("\n");
 
955
}
 
956
#else
 
957
static void of_dump_addr(const char *s, const fdt32_t *addr, int na) { }
 
958
#endif
 
959
 
 
960
/* Callbacks for bus specific translators */
 
961
struct of_bus {
 
962
        const char      *name;
 
963
        const char      *addresses;
 
964
        void            (*count_cells)(void *blob, int parentoffset,
 
965
                                int *addrc, int *sizec);
 
966
        u64             (*map)(fdt32_t *addr, const fdt32_t *range,
 
967
                                int na, int ns, int pna);
 
968
        int             (*translate)(fdt32_t *addr, u64 offset, int na);
 
969
};
 
970
 
 
971
/* Default translator (generic bus) */
 
972
static void of_bus_default_count_cells(void *blob, int parentoffset,
 
973
                                        int *addrc, int *sizec)
 
974
{
 
975
        const fdt32_t *prop;
 
976
 
 
977
        if (addrc) {
 
978
                prop = fdt_getprop(blob, parentoffset, "#address-cells", NULL);
 
979
                if (prop)
 
980
                        *addrc = be32_to_cpup(prop);
 
981
                else
 
982
                        *addrc = 2;
 
983
        }
 
984
 
 
985
        if (sizec) {
 
986
                prop = fdt_getprop(blob, parentoffset, "#size-cells", NULL);
 
987
                if (prop)
 
988
                        *sizec = be32_to_cpup(prop);
 
989
                else
 
990
                        *sizec = 1;
 
991
        }
 
992
}
 
993
 
 
994
static u64 of_bus_default_map(fdt32_t *addr, const fdt32_t *range,
 
995
                int na, int ns, int pna)
 
996
{
 
997
        u64 cp, s, da;
 
998
 
 
999
        cp = of_read_number(range, na);
 
1000
        s  = of_read_number(range + na + pna, ns);
 
1001
        da = of_read_number(addr, na);
 
1002
 
 
1003
        debug("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n",
 
1004
            cp, s, da);
 
1005
 
 
1006
        if (da < cp || da >= (cp + s))
 
1007
                return OF_BAD_ADDR;
 
1008
        return da - cp;
 
1009
}
 
1010
 
 
1011
static int of_bus_default_translate(fdt32_t *addr, u64 offset, int na)
 
1012
{
 
1013
        u64 a = of_read_number(addr, na);
 
1014
        memset(addr, 0, na * 4);
 
1015
        a += offset;
 
1016
        if (na > 1)
 
1017
                addr[na - 2] = cpu_to_fdt32(a >> 32);
 
1018
        addr[na - 1] = cpu_to_fdt32(a & 0xffffffffu);
 
1019
 
 
1020
        return 0;
 
1021
}
 
1022
 
 
1023
/* Array of bus specific translators */
 
1024
static struct of_bus of_busses[] = {
 
1025
        /* Default */
 
1026
        {
 
1027
                .name = "default",
 
1028
                .addresses = "reg",
 
1029
                .count_cells = of_bus_default_count_cells,
 
1030
                .map = of_bus_default_map,
 
1031
                .translate = of_bus_default_translate,
 
1032
        },
 
1033
};
 
1034
 
 
1035
static int of_translate_one(void * blob, int parent, struct of_bus *bus,
 
1036
                            struct of_bus *pbus, fdt32_t *addr,
 
1037
                            int na, int ns, int pna, const char *rprop)
 
1038
{
 
1039
        const fdt32_t *ranges;
 
1040
        int rlen;
 
1041
        int rone;
 
1042
        u64 offset = OF_BAD_ADDR;
 
1043
 
 
1044
        /* Normally, an absence of a "ranges" property means we are
 
1045
         * crossing a non-translatable boundary, and thus the addresses
 
1046
         * below the current not cannot be converted to CPU physical ones.
 
1047
         * Unfortunately, while this is very clear in the spec, it's not
 
1048
         * what Apple understood, and they do have things like /uni-n or
 
1049
         * /ht nodes with no "ranges" property and a lot of perfectly
 
1050
         * useable mapped devices below them. Thus we treat the absence of
 
1051
         * "ranges" as equivalent to an empty "ranges" property which means
 
1052
         * a 1:1 translation at that level. It's up to the caller not to try
 
1053
         * to translate addresses that aren't supposed to be translated in
 
1054
         * the first place. --BenH.
 
1055
         */
 
1056
        ranges = fdt_getprop(blob, parent, rprop, &rlen);
 
1057
        if (ranges == NULL || rlen == 0) {
 
1058
                offset = of_read_number(addr, na);
 
1059
                memset(addr, 0, pna * 4);
 
1060
                debug("OF: no ranges, 1:1 translation\n");
 
1061
                goto finish;
 
1062
        }
 
1063
 
 
1064
        debug("OF: walking ranges...\n");
 
1065
 
 
1066
        /* Now walk through the ranges */
 
1067
        rlen /= 4;
 
1068
        rone = na + pna + ns;
 
1069
        for (; rlen >= rone; rlen -= rone, ranges += rone) {
 
1070
                offset = bus->map(addr, ranges, na, ns, pna);
 
1071
                if (offset != OF_BAD_ADDR)
 
1072
                        break;
 
1073
        }
 
1074
        if (offset == OF_BAD_ADDR) {
 
1075
                debug("OF: not found !\n");
 
1076
                return 1;
 
1077
        }
 
1078
        memcpy(addr, ranges + na, 4 * pna);
 
1079
 
 
1080
 finish:
 
1081
        of_dump_addr("OF: parent translation for:", addr, pna);
 
1082
        debug("OF: with offset: "PRu64"\n", offset);
 
1083
 
 
1084
        /* Translate it into parent bus space */
 
1085
        return pbus->translate(addr, offset, pna);
 
1086
}
 
1087
 
 
1088
/*
 
1089
 * Translate an address from the device-tree into a CPU physical address,
 
1090
 * this walks up the tree and applies the various bus mappings on the
 
1091
 * way.
 
1092
 *
 
1093
 * Note: We consider that crossing any level with #size-cells == 0 to mean
 
1094
 * that translation is impossible (that is we are not dealing with a value
 
1095
 * that can be mapped to a cpu physical address). This is not really specified
 
1096
 * that way, but this is traditionally the way IBM at least do things
 
1097
 */
 
1098
static u64 __of_translate_address(void *blob, int node_offset, const fdt32_t *in_addr,
 
1099
                                  const char *rprop)
 
1100
{
 
1101
        int parent;
 
1102
        struct of_bus *bus, *pbus;
 
1103
        fdt32_t addr[OF_MAX_ADDR_CELLS];
 
1104
        int na, ns, pna, pns;
 
1105
        u64 result = OF_BAD_ADDR;
 
1106
 
 
1107
        debug("OF: ** translation for device %s **\n",
 
1108
                fdt_get_name(blob, node_offset, NULL));
 
1109
 
 
1110
        /* Get parent & match bus type */
 
1111
        parent = fdt_parent_offset(blob, node_offset);
 
1112
        if (parent < 0)
 
1113
                goto bail;
 
1114
        bus = &of_busses[0];
 
1115
 
 
1116
        /* Cound address cells & copy address locally */
 
1117
        bus->count_cells(blob, parent, &na, &ns);
 
1118
        if (!OF_CHECK_COUNTS(na, ns)) {
 
1119
                printf("%s: Bad cell count for %s\n", __FUNCTION__,
 
1120
                       fdt_get_name(blob, node_offset, NULL));
 
1121
                goto bail;
 
1122
        }
 
1123
        memcpy(addr, in_addr, na * 4);
 
1124
 
 
1125
        debug("OF: bus is %s (na=%d, ns=%d) on %s\n",
 
1126
            bus->name, na, ns, fdt_get_name(blob, parent, NULL));
 
1127
        of_dump_addr("OF: translating address:", addr, na);
 
1128
 
 
1129
        /* Translate */
 
1130
        for (;;) {
 
1131
                /* Switch to parent bus */
 
1132
                node_offset = parent;
 
1133
                parent = fdt_parent_offset(blob, node_offset);
 
1134
 
 
1135
                /* If root, we have finished */
 
1136
                if (parent < 0) {
 
1137
                        debug("OF: reached root node\n");
 
1138
                        result = of_read_number(addr, na);
 
1139
                        break;
 
1140
                }
 
1141
 
 
1142
                /* Get new parent bus and counts */
 
1143
                pbus = &of_busses[0];
 
1144
                pbus->count_cells(blob, parent, &pna, &pns);
 
1145
                if (!OF_CHECK_COUNTS(pna, pns)) {
 
1146
                        printf("%s: Bad cell count for %s\n", __FUNCTION__,
 
1147
                                fdt_get_name(blob, node_offset, NULL));
 
1148
                        break;
 
1149
                }
 
1150
 
 
1151
                debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
 
1152
                    pbus->name, pna, pns, fdt_get_name(blob, parent, NULL));
 
1153
 
 
1154
                /* Apply bus translation */
 
1155
                if (of_translate_one(blob, node_offset, bus, pbus,
 
1156
                                        addr, na, ns, pna, rprop))
 
1157
                        break;
 
1158
 
 
1159
                /* Complete the move up one level */
 
1160
                na = pna;
 
1161
                ns = pns;
 
1162
                bus = pbus;
 
1163
 
 
1164
                of_dump_addr("OF: one level translation:", addr, na);
 
1165
        }
 
1166
 bail:
 
1167
 
 
1168
        return result;
 
1169
}
 
1170
 
 
1171
u64 fdt_translate_address(void *blob, int node_offset, const fdt32_t *in_addr)
 
1172
{
 
1173
        return __of_translate_address(blob, node_offset, in_addr, "ranges");
 
1174
}
 
1175
 
 
1176
/**
 
1177
 * fdt_node_offset_by_compat_reg: Find a node that matches compatiable and
 
1178
 * who's reg property matches a physical cpu address
 
1179
 *
 
1180
 * @blob: ptr to device tree
 
1181
 * @compat: compatiable string to match
 
1182
 * @compat_off: property name
 
1183
 *
 
1184
 */
 
1185
int fdt_node_offset_by_compat_reg(void *blob, const char *compat,
 
1186
                                        phys_addr_t compat_off)
 
1187
{
 
1188
        int len, off = fdt_node_offset_by_compatible(blob, -1, compat);
 
1189
        while (off != -FDT_ERR_NOTFOUND) {
 
1190
                const fdt32_t *reg = fdt_getprop(blob, off, "reg", &len);
 
1191
                if (reg) {
 
1192
                        if (compat_off == fdt_translate_address(blob, off, reg))
 
1193
                                return off;
 
1194
                }
 
1195
                off = fdt_node_offset_by_compatible(blob, off, compat);
 
1196
        }
 
1197
 
 
1198
        return -FDT_ERR_NOTFOUND;
 
1199
}
 
1200
 
 
1201
/**
 
1202
 * fdt_alloc_phandle: Return next free phandle value
 
1203
 *
 
1204
 * @blob: ptr to device tree
 
1205
 */
 
1206
int fdt_alloc_phandle(void *blob)
 
1207
{
 
1208
        int offset, phandle = 0;
 
1209
 
 
1210
        for (offset = fdt_next_node(blob, -1, NULL); offset >= 0;
 
1211
             offset = fdt_next_node(blob, offset, NULL)) {
 
1212
                phandle = max(phandle, fdt_get_phandle(blob, offset));
 
1213
        }
 
1214
 
 
1215
        return phandle + 1;
 
1216
}
 
1217
 
 
1218
/*
 
1219
 * fdt_set_phandle: Create a phandle property for the given node
 
1220
 *
 
1221
 * @fdt: ptr to device tree
 
1222
 * @nodeoffset: node to update
 
1223
 * @phandle: phandle value to set (must be unique)
 
1224
 */
 
1225
int fdt_set_phandle(void *fdt, int nodeoffset, uint32_t phandle)
 
1226
{
 
1227
        int ret;
 
1228
 
 
1229
#ifdef DEBUG
 
1230
        int off = fdt_node_offset_by_phandle(fdt, phandle);
 
1231
 
 
1232
        if ((off >= 0) && (off != nodeoffset)) {
 
1233
                char buf[64];
 
1234
 
 
1235
                fdt_get_path(fdt, nodeoffset, buf, sizeof(buf));
 
1236
                printf("Trying to update node %s with phandle %u ",
 
1237
                       buf, phandle);
 
1238
 
 
1239
                fdt_get_path(fdt, off, buf, sizeof(buf));
 
1240
                printf("that already exists in node %s.\n", buf);
 
1241
                return -FDT_ERR_BADPHANDLE;
 
1242
        }
 
1243
#endif
 
1244
 
 
1245
        ret = fdt_setprop_cell(fdt, nodeoffset, "phandle", phandle);
 
1246
        if (ret < 0)
 
1247
                return ret;
 
1248
 
 
1249
        /*
 
1250
         * For now, also set the deprecated "linux,phandle" property, so that we
 
1251
         * don't break older kernels.
 
1252
         */
 
1253
        ret = fdt_setprop_cell(fdt, nodeoffset, "linux,phandle", phandle);
 
1254
 
 
1255
        return ret;
 
1256
}
 
1257
 
 
1258
/*
 
1259
 * fdt_create_phandle: Create a phandle property for the given node
 
1260
 *
 
1261
 * @fdt: ptr to device tree
 
1262
 * @nodeoffset: node to update
 
1263
 */
 
1264
unsigned int fdt_create_phandle(void *fdt, int nodeoffset)
 
1265
{
 
1266
        /* see if there is a phandle already */
 
1267
        int phandle = fdt_get_phandle(fdt, nodeoffset);
 
1268
 
 
1269
        /* if we got 0, means no phandle so create one */
 
1270
        if (phandle == 0) {
 
1271
                int ret;
 
1272
 
 
1273
                phandle = fdt_alloc_phandle(fdt);
 
1274
                ret = fdt_set_phandle(fdt, nodeoffset, phandle);
 
1275
                if (ret < 0) {
 
1276
                        printf("Can't set phandle %u: %s\n", phandle,
 
1277
                               fdt_strerror(ret));
 
1278
                        return 0;
 
1279
                }
 
1280
        }
 
1281
 
 
1282
        return phandle;
 
1283
}
 
1284
 
 
1285
/*
 
1286
 * fdt_set_node_status: Set status for the given node
 
1287
 *
 
1288
 * @fdt: ptr to device tree
 
1289
 * @nodeoffset: node to update
 
1290
 * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED,
 
1291
 *          FDT_STATUS_FAIL, FDT_STATUS_FAIL_ERROR_CODE
 
1292
 * @error_code: optional, only used if status is FDT_STATUS_FAIL_ERROR_CODE
 
1293
 */
 
1294
int fdt_set_node_status(void *fdt, int nodeoffset,
 
1295
                        enum fdt_status status, unsigned int error_code)
 
1296
{
 
1297
        char buf[16];
 
1298
        int ret = 0;
 
1299
 
 
1300
        if (nodeoffset < 0)
 
1301
                return nodeoffset;
 
1302
 
 
1303
        switch (status) {
 
1304
        case FDT_STATUS_OKAY:
 
1305
                ret = fdt_setprop_string(fdt, nodeoffset, "status", "okay");
 
1306
                break;
 
1307
        case FDT_STATUS_DISABLED:
 
1308
                ret = fdt_setprop_string(fdt, nodeoffset, "status", "disabled");
 
1309
                break;
 
1310
        case FDT_STATUS_FAIL:
 
1311
                ret = fdt_setprop_string(fdt, nodeoffset, "status", "fail");
 
1312
                break;
 
1313
        case FDT_STATUS_FAIL_ERROR_CODE:
 
1314
                sprintf(buf, "fail-%d", error_code);
 
1315
                ret = fdt_setprop_string(fdt, nodeoffset, "status", buf);
 
1316
                break;
 
1317
        default:
 
1318
                printf("Invalid fdt status: %x\n", status);
 
1319
                ret = -1;
 
1320
                break;
 
1321
        }
 
1322
 
 
1323
        return ret;
 
1324
}
 
1325
 
 
1326
/*
 
1327
 * fdt_set_status_by_alias: Set status for the given node given an alias
 
1328
 *
 
1329
 * @fdt: ptr to device tree
 
1330
 * @alias: alias of node to update
 
1331
 * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED,
 
1332
 *          FDT_STATUS_FAIL, FDT_STATUS_FAIL_ERROR_CODE
 
1333
 * @error_code: optional, only used if status is FDT_STATUS_FAIL_ERROR_CODE
 
1334
 */
 
1335
int fdt_set_status_by_alias(void *fdt, const char* alias,
 
1336
                            enum fdt_status status, unsigned int error_code)
 
1337
{
 
1338
        int offset = fdt_path_offset(fdt, alias);
 
1339
 
 
1340
        return fdt_set_node_status(fdt, offset, status, error_code);
 
1341
}
 
1342
 
 
1343
#if defined(CONFIG_VIDEO) || defined(CONFIG_LCD)
 
1344
int fdt_add_edid(void *blob, const char *compat, unsigned char *edid_buf)
 
1345
{
 
1346
        int noff;
 
1347
        int ret;
 
1348
 
 
1349
        noff = fdt_node_offset_by_compatible(blob, -1, compat);
 
1350
        if (noff != -FDT_ERR_NOTFOUND) {
 
1351
                debug("%s: %s\n", fdt_get_name(blob, noff, 0), compat);
 
1352
add_edid:
 
1353
                ret = fdt_setprop(blob, noff, "edid", edid_buf, 128);
 
1354
                if (ret == -FDT_ERR_NOSPACE) {
 
1355
                        ret = fdt_increase_size(blob, 512);
 
1356
                        if (!ret)
 
1357
                                goto add_edid;
 
1358
                        else
 
1359
                                goto err_size;
 
1360
                } else if (ret < 0) {
 
1361
                        printf("Can't add property: %s\n", fdt_strerror(ret));
 
1362
                        return ret;
 
1363
                }
 
1364
        }
 
1365
        return 0;
 
1366
err_size:
 
1367
        printf("Can't increase blob size: %s\n", fdt_strerror(ret));
 
1368
        return ret;
 
1369
}
 
1370
#endif
 
1371
 
 
1372
/*
 
1373
 * Verify the physical address of device tree node for a given alias
 
1374
 *
 
1375
 * This function locates the device tree node of a given alias, and then
 
1376
 * verifies that the physical address of that device matches the given
 
1377
 * parameter.  It displays a message if there is a mismatch.
 
1378
 *
 
1379
 * Returns 1 on success, 0 on failure
 
1380
 */
 
1381
int fdt_verify_alias_address(void *fdt, int anode, const char *alias, u64 addr)
 
1382
{
 
1383
        const char *path;
 
1384
        const fdt32_t *reg;
 
1385
        int node, len;
 
1386
        u64 dt_addr;
 
1387
 
 
1388
        path = fdt_getprop(fdt, anode, alias, NULL);
 
1389
        if (!path) {
 
1390
                /* If there's no such alias, then it's not a failure */
 
1391
                return 1;
 
1392
        }
 
1393
 
 
1394
        node = fdt_path_offset(fdt, path);
 
1395
        if (node < 0) {
 
1396
                printf("Warning: device tree alias '%s' points to invalid "
 
1397
                       "node %s.\n", alias, path);
 
1398
                return 0;
 
1399
        }
 
1400
 
 
1401
        reg = fdt_getprop(fdt, node, "reg", &len);
 
1402
        if (!reg) {
 
1403
                printf("Warning: device tree node '%s' has no address.\n",
 
1404
                       path);
 
1405
                return 0;
 
1406
        }
 
1407
 
 
1408
        dt_addr = fdt_translate_address(fdt, node, reg);
 
1409
        if (addr != dt_addr) {
 
1410
                printf("Warning: U-Boot configured device %s at address %llx,\n"
 
1411
                       " but the device tree has it address %llx.\n",
 
1412
                       alias, addr, dt_addr);
 
1413
                return 0;
 
1414
        }
 
1415
 
 
1416
        return 1;
 
1417
}
 
1418
 
 
1419
/*
 
1420
 * Returns the base address of an SOC or PCI node
 
1421
 */
 
1422
u64 fdt_get_base_address(void *fdt, int node)
 
1423
{
 
1424
        int size;
 
1425
        u32 naddr;
 
1426
        const fdt32_t *prop;
 
1427
 
 
1428
        prop = fdt_getprop(fdt, node, "#address-cells", &size);
 
1429
        if (prop && size == 4)
 
1430
                naddr = be32_to_cpup(prop);
 
1431
        else
 
1432
                naddr = 2;
 
1433
 
 
1434
        prop = fdt_getprop(fdt, node, "ranges", &size);
 
1435
 
 
1436
        return prop ? fdt_translate_address(fdt, node, prop + naddr) : 0;
 
1437
}
 
1438
 
 
1439
/*
 
1440
 * Read a property of size <prop_len>. Currently only supports 1 or 2 cells.
 
1441
 */
 
1442
static int fdt_read_prop(const fdt32_t *prop, int prop_len, int cell_off,
 
1443
                         uint64_t *val, int cells)
 
1444
{
 
1445
        const fdt32_t *prop32 = &prop[cell_off];
 
1446
        const fdt64_t *prop64 = (const fdt64_t *)&prop[cell_off];
 
1447
 
 
1448
        if ((cell_off + cells) > prop_len)
 
1449
                return -FDT_ERR_NOSPACE;
 
1450
 
 
1451
        switch (cells) {
 
1452
        case 1:
 
1453
                *val = fdt32_to_cpu(*prop32);
 
1454
                break;
 
1455
        case 2:
 
1456
                *val = fdt64_to_cpu(*prop64);
 
1457
                break;
 
1458
        default:
 
1459
                return -FDT_ERR_NOSPACE;
 
1460
        }
 
1461
 
 
1462
        return 0;
 
1463
}
 
1464
 
 
1465
/**
 
1466
 * fdt_read_range - Read a node's n'th range property
 
1467
 *
 
1468
 * @fdt: ptr to device tree
 
1469
 * @node: offset of node
 
1470
 * @n: range index
 
1471
 * @child_addr: pointer to storage for the "child address" field
 
1472
 * @addr: pointer to storage for the CPU view translated physical start
 
1473
 * @len: pointer to storage for the range length
 
1474
 *
 
1475
 * Convenience function that reads and interprets a specific range out of
 
1476
 * a number of the "ranges" property array.
 
1477
 */
 
1478
int fdt_read_range(void *fdt, int node, int n, uint64_t *child_addr,
 
1479
                   uint64_t *addr, uint64_t *len)
 
1480
{
 
1481
        int pnode = fdt_parent_offset(fdt, node);
 
1482
        const fdt32_t *ranges;
 
1483
        int pacells;
 
1484
        int acells;
 
1485
        int scells;
 
1486
        int ranges_len;
 
1487
        int cell = 0;
 
1488
        int r = 0;
 
1489
 
 
1490
        /*
 
1491
         * The "ranges" property is an array of
 
1492
         * { <child address> <parent address> <size in child address space> }
 
1493
         *
 
1494
         * All 3 elements can span a diffent number of cells. Fetch their size.
 
1495
         */
 
1496
        pacells = fdt_getprop_u32_default_node(fdt, pnode, 0, "#address-cells", 1);
 
1497
        acells = fdt_getprop_u32_default_node(fdt, node, 0, "#address-cells", 1);
 
1498
        scells = fdt_getprop_u32_default_node(fdt, node, 0, "#size-cells", 1);
 
1499
 
 
1500
        /* Now try to get the ranges property */
 
1501
        ranges = fdt_getprop(fdt, node, "ranges", &ranges_len);
 
1502
        if (!ranges)
 
1503
                return -FDT_ERR_NOTFOUND;
 
1504
        ranges_len /= sizeof(uint32_t);
 
1505
 
 
1506
        /* Jump to the n'th entry */
 
1507
        cell = n * (pacells + acells + scells);
 
1508
 
 
1509
        /* Read <child address> */
 
1510
        if (child_addr) {
 
1511
                r = fdt_read_prop(ranges, ranges_len, cell, child_addr,
 
1512
                                  acells);
 
1513
                if (r)
 
1514
                        return r;
 
1515
        }
 
1516
        cell += acells;
 
1517
 
 
1518
        /* Read <parent address> */
 
1519
        if (addr)
 
1520
                *addr = fdt_translate_address(fdt, node, ranges + cell);
 
1521
        cell += pacells;
 
1522
 
 
1523
        /* Read <size in child address space> */
 
1524
        if (len) {
 
1525
                r = fdt_read_prop(ranges, ranges_len, cell, len, scells);
 
1526
                if (r)
 
1527
                        return r;
 
1528
        }
 
1529
 
 
1530
        return 0;
 
1531
}