17459eface0cebca1bf2183efabd9a6b5055abcb
[openwrt/staging/chunkeey.git] / target / linux / mpc85xx / files / arch / powerpc / boot / cuboot-tl-wdr4900-v1.c
1 /*
2 * U-Boot compatibility wrapper for the TP-Link TL-WDR4900 v1 board
3 *
4 * Copyright (c) 2013 Gabor Juhos <juhosg@openwrt.org>
5 *
6 * Based on:
7 * cuboot-85xx.c
8 * Author: Scott Wood <scottwood@freescale.com>
9 * Copyright (c) 2007 Freescale Semiconductor, Inc.
10 *
11 * simpleboot.c
12 * Authors: Scott Wood <scottwood@freescale.com>
13 * Grant Likely <grant.likely@secretlab.ca>
14 * Copyright (c) 2007 Freescale Semiconductor, Inc.
15 * Copyright (c) 2008 Secret Lab Technologies Ltd.
16 *
17 * This program is free software; you can redistribute it and/or modify it
18 * under the terms of the GNU General Public License version 2 as published
19 * by the Free Software Foundation.
20 */
21
22 #include "ops.h"
23 #include "types.h"
24 #include "io.h"
25 #include "stdio.h"
26 #include <libfdt.h>
27
28 BSS_STACK(4*1024);
29
30 static unsigned long bus_freq;
31 static unsigned long int_freq;
32 static u64 mem_size;
33 static unsigned char enetaddr[6];
34
35 static void process_boot_dtb(void *boot_dtb)
36 {
37 const u32 *na, *ns, *reg, *val32;
38 const char *path;
39 u64 memsize64;
40 int node, size, i;
41
42 /* Make sure FDT blob is sane */
43 if (fdt_check_header(boot_dtb) != 0)
44 fatal("Invalid device tree blob\n");
45
46 /* Find the #address-cells and #size-cells properties */
47 node = fdt_path_offset(boot_dtb, "/");
48 if (node < 0)
49 fatal("Cannot find root node\n");
50 na = fdt_getprop(boot_dtb, node, "#address-cells", &size);
51 if (!na || (size != 4))
52 fatal("Cannot find #address-cells property");
53
54 ns = fdt_getprop(boot_dtb, node, "#size-cells", &size);
55 if (!ns || (size != 4))
56 fatal("Cannot find #size-cells property");
57
58 /* Find the memory range */
59 node = fdt_node_offset_by_prop_value(boot_dtb, -1, "device_type",
60 "memory", sizeof("memory"));
61 if (node < 0)
62 fatal("Cannot find memory node\n");
63 reg = fdt_getprop(boot_dtb, node, "reg", &size);
64 if (size < (*na+*ns) * sizeof(u32))
65 fatal("cannot get memory range\n");
66
67 /* Only interested in memory based at 0 */
68 for (i = 0; i < *na; i++)
69 if (*reg++ != 0)
70 fatal("Memory range is not based at address 0\n");
71
72 /* get the memsize and trucate it to under 4G on 32 bit machines */
73 memsize64 = 0;
74 for (i = 0; i < *ns; i++)
75 memsize64 = (memsize64 << 32) | *reg++;
76 if (sizeof(void *) == 4 && memsize64 >= 0x100000000ULL)
77 memsize64 = 0xffffffff;
78
79 mem_size = memsize64;
80
81 /* get clock frequencies */
82 node = fdt_node_offset_by_prop_value(boot_dtb, -1, "device_type",
83 "cpu", sizeof("cpu"));
84 if (!node)
85 fatal("Cannot find cpu node\n");
86
87 val32 = fdt_getprop(boot_dtb, node, "clock-frequency", &size);
88 if (!val32 || (size != 4))
89 fatal("Cannot get clock frequency");
90
91 int_freq = *val32;
92
93 val32 = fdt_getprop(boot_dtb, node, "bus-frequency", &size);
94 if (!val32 || (size != 4))
95 fatal("Cannot get bus frequency");
96
97 bus_freq = *val32;
98
99 path = fdt_get_alias(boot_dtb, "ethernet0");
100 if (path) {
101 const void *p;
102
103 node = fdt_path_offset(boot_dtb, path);
104 if (node < 0)
105 fatal("Cannot find ethernet0 node");
106
107 p = fdt_getprop(boot_dtb, node, "mac-address", &size);
108 if (!p || (size < 6)) {
109 printf("no mac-address property, finding local\n\r");
110 p = fdt_getprop(boot_dtb, node, "local-mac-address", &size);
111 }
112
113 if (!p || (size < 6))
114 fatal("cannot get MAC addres");
115
116 memcpy(enetaddr, p, sizeof(enetaddr));
117 }
118 }
119
120 static void platform_fixups(void)
121 {
122 void *soc, *mpic;
123
124 dt_fixup_memory(0, mem_size);
125
126 dt_fixup_mac_address_by_alias("ethernet0", enetaddr);
127 dt_fixup_cpu_clocks(int_freq, bus_freq / 8, bus_freq);
128
129 /* Unfortunately, the specific model number is encoded in the
130 * soc node name in existing dts files -- once that is fixed,
131 * this can do a simple path lookup.
132 */
133 soc = find_node_by_devtype(NULL, "soc");
134 if (soc) {
135 void *serial = NULL;
136
137 setprop(soc, "bus-frequency", &bus_freq, sizeof(bus_freq));
138
139 while ((serial = find_node_by_devtype(serial, "serial"))) {
140 if (get_parent(serial) != soc)
141 continue;
142
143 setprop(serial, "clock-frequency", &bus_freq,
144 sizeof(bus_freq));
145 }
146 }
147
148 mpic = find_node_by_compatible(NULL, "fsl,mpic");
149 if (mpic)
150 setprop(mpic, "clock-frequency", &bus_freq, sizeof(bus_freq));
151 }
152
153 void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
154 unsigned long r6, unsigned long r7)
155 {
156 mem_size = 64 * 1024 * 1024;
157
158 simple_alloc_init(_end, mem_size - (u32)_end - 1024*1024, 32, 64);
159
160 fdt_init(_dtb_start);
161 serial_console_init();
162
163 printf("\n\r-- TL-WDR4900 v1 boot wrapper --\n\r");
164
165 process_boot_dtb((void *) r3);
166
167 platform_ops.fixups = platform_fixups;
168 }