]> Pileus Git - ~andy/linux/blob - arch/xtensa/platforms/xtfpga/setup.c
xtensa: set the correct ethernet address for xtfpga
[~andy/linux] / arch / xtensa / platforms / xtfpga / setup.c
1 /*
2  *
3  * arch/xtensa/platform/xtavnet/setup.c
4  *
5  * ...
6  *
7  * Authors:     Chris Zankel <chris@zankel.net>
8  *              Joe Taylor <joe@tensilica.com>
9  *
10  * Copyright 2001 - 2006 Tensilica Inc.
11  *
12  * This program is free software; you can redistribute  it and/or modify it
13  * under  the terms of  the GNU General  Public License as published by the
14  * Free Software Foundation;  either version 2 of the  License, or (at your
15  * option) any later version.
16  *
17  */
18 #include <linux/stddef.h>
19 #include <linux/kernel.h>
20 #include <linux/init.h>
21 #include <linux/errno.h>
22 #include <linux/reboot.h>
23 #include <linux/kdev_t.h>
24 #include <linux/types.h>
25 #include <linux/major.h>
26 #include <linux/console.h>
27 #include <linux/delay.h>
28 #include <linux/of.h>
29
30 #include <asm/timex.h>
31 #include <asm/processor.h>
32 #include <asm/platform.h>
33 #include <asm/bootparam.h>
34 #include <platform/lcd.h>
35 #include <platform/hardware.h>
36
37 void platform_halt(void)
38 {
39         lcd_disp_at_pos(" HALT ", 0);
40         local_irq_disable();
41         while (1)
42                 cpu_relax();
43 }
44
45 void platform_power_off(void)
46 {
47         lcd_disp_at_pos("POWEROFF", 0);
48         local_irq_disable();
49         while (1)
50                 cpu_relax();
51 }
52
53 void platform_restart(void)
54 {
55         /* Flush and reset the mmu, simulate a processor reset, and
56          * jump to the reset vector. */
57
58
59         __asm__ __volatile__ ("movi     a2, 15\n\t"
60                               "wsr      a2, icountlevel\n\t"
61                               "movi     a2, 0\n\t"
62                               "wsr      a2, icount\n\t"
63                               "wsr      a2, ibreakenable\n\t"
64                               "wsr      a2, lcount\n\t"
65                               "movi     a2, 0x1f\n\t"
66                               "wsr      a2, ps\n\t"
67                               "isync\n\t"
68                               "jx       %0\n\t"
69                               :
70                               : "a" (XCHAL_RESET_VECTOR_VADDR)
71                               : "a2"
72                               );
73
74         /* control never gets here */
75 }
76
77 void __init platform_setup(char **cmdline)
78 {
79 }
80
81 #ifdef CONFIG_OF
82
83 static void __init update_clock_frequency(struct device_node *node)
84 {
85         struct property *newfreq;
86         u32 freq;
87
88         if (!of_property_read_u32(node, "clock-frequency", &freq) && freq != 0)
89                 return;
90
91         newfreq = kzalloc(sizeof(*newfreq) + sizeof(u32), GFP_KERNEL);
92         if (!newfreq)
93                 return;
94         newfreq->value = newfreq + 1;
95         newfreq->length = sizeof(freq);
96         newfreq->name = kstrdup("clock-frequency", GFP_KERNEL);
97         if (!newfreq->name) {
98                 kfree(newfreq);
99                 return;
100         }
101
102         *(u32 *)newfreq->value = cpu_to_be32(*(u32 *)XTFPGA_CLKFRQ_VADDR);
103         prom_update_property(node, newfreq);
104 }
105
106 #define MAC_LEN 6
107 static void __init update_local_mac(struct device_node *node)
108 {
109         struct property *newmac;
110         const u8* macaddr;
111         int prop_len;
112
113         macaddr = of_get_property(node, "local-mac-address", &prop_len);
114         if (macaddr == NULL || prop_len != MAC_LEN)
115                 return;
116
117         newmac = kzalloc(sizeof(*newmac) + MAC_LEN, GFP_KERNEL);
118         if (newmac == NULL)
119                 return;
120
121         newmac->value = newmac + 1;
122         newmac->length = MAC_LEN;
123         newmac->name = kstrdup("local-mac-address", GFP_KERNEL);
124         if (newmac->name == NULL) {
125                 kfree(newmac);
126                 return;
127         }
128
129         memcpy(newmac->value, macaddr, MAC_LEN);
130         ((u8*)newmac->value)[5] = (*(u32*)DIP_SWITCHES_VADDR) & 0x3f;
131         prom_update_property(node, newmac);
132 }
133
134 static int __init machine_setup(void)
135 {
136         struct device_node *serial;
137         struct device_node *eth = NULL;
138
139         for_each_compatible_node(serial, NULL, "ns16550a")
140                 update_clock_frequency(serial);
141
142         if ((eth = of_find_compatible_node(eth, NULL, "opencores,ethoc")))
143                 update_local_mac(eth);
144         return 0;
145 }
146 arch_initcall(machine_setup);
147
148 #endif
149
150 /* early initialization */
151
152 void __init platform_init(bp_tag_t *first)
153 {
154 }
155
156 /* Heartbeat. */
157
158 void platform_heartbeat(void)
159 {
160 }
161
162 #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
163
164 void platform_calibrate_ccount(void)
165 {
166         long clk_freq = 0;
167 #ifdef CONFIG_OF
168         struct device_node *cpu =
169                 of_find_compatible_node(NULL, NULL, "xtensa,cpu");
170         if (cpu) {
171                 u32 freq;
172                 update_clock_frequency(cpu);
173                 if (!of_property_read_u32(cpu, "clock-frequency", &freq))
174                         clk_freq = freq;
175         }
176 #endif
177         if (!clk_freq)
178                 clk_freq = *(long *)XTFPGA_CLKFRQ_VADDR;
179
180         ccount_per_jiffy = clk_freq / HZ;
181         nsec_per_ccount = 1000000000UL / clk_freq;
182 }
183
184 #endif
185
186 #ifndef CONFIG_OF
187
188 #include <linux/serial_8250.h>
189 #include <linux/if.h>
190 #include <net/ethoc.h>
191
192 /*----------------------------------------------------------------------------
193  *  Ethernet -- OpenCores Ethernet MAC (ethoc driver)
194  */
195
196 static struct resource ethoc_res[] __initdata = {
197         [0] = { /* register space */
198                 .start = OETH_REGS_PADDR,
199                 .end   = OETH_REGS_PADDR + OETH_REGS_SIZE - 1,
200                 .flags = IORESOURCE_MEM,
201         },
202         [1] = { /* buffer space */
203                 .start = OETH_SRAMBUFF_PADDR,
204                 .end   = OETH_SRAMBUFF_PADDR + OETH_SRAMBUFF_SIZE - 1,
205                 .flags = IORESOURCE_MEM,
206         },
207         [2] = { /* IRQ number */
208                 .start = OETH_IRQ,
209                 .end   = OETH_IRQ,
210                 .flags = IORESOURCE_IRQ,
211         },
212 };
213
214 static struct ethoc_platform_data ethoc_pdata __initdata = {
215         /*
216          * The MAC address for these boards is 00:50:c2:13:6f:xx.
217          * The last byte (here as zero) is read from the DIP switches on the
218          * board.
219          */
220         .hwaddr = { 0x00, 0x50, 0xc2, 0x13, 0x6f, 0 },
221         .phy_id = -1,
222 };
223
224 static struct platform_device ethoc_device __initdata = {
225         .name = "ethoc",
226         .id = -1,
227         .num_resources = ARRAY_SIZE(ethoc_res),
228         .resource = ethoc_res,
229         .dev = {
230                 .platform_data = &ethoc_pdata,
231         },
232 };
233
234 /*----------------------------------------------------------------------------
235  *  UART
236  */
237
238 static struct resource serial_resource __initdata = {
239         .start  = DUART16552_PADDR,
240         .end    = DUART16552_PADDR + 0x1f,
241         .flags  = IORESOURCE_MEM,
242 };
243
244 static struct plat_serial8250_port serial_platform_data[] __initdata = {
245         [0] = {
246                 .mapbase        = DUART16552_PADDR,
247                 .irq            = DUART16552_INTNUM,
248                 .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
249                                   UPF_IOREMAP,
250                 .iotype         = UPIO_MEM32,
251                 .regshift       = 2,
252                 .uartclk        = 0,    /* set in xtavnet_init() */
253         },
254         { },
255 };
256
257 static struct platform_device xtavnet_uart __initdata = {
258         .name           = "serial8250",
259         .id             = PLAT8250_DEV_PLATFORM,
260         .dev            = {
261                 .platform_data  = serial_platform_data,
262         },
263         .num_resources  = 1,
264         .resource       = &serial_resource,
265 };
266
267 /* platform devices */
268 static struct platform_device *platform_devices[] __initdata = {
269         &ethoc_device,
270         &xtavnet_uart,
271 };
272
273
274 static int __init xtavnet_init(void)
275 {
276         /* Ethernet MAC address.  */
277         ethoc_pdata.hwaddr[5] = *(u32 *)DIP_SWITCHES_VADDR;
278
279         /* Clock rate varies among FPGA bitstreams; board specific FPGA register
280          * reports the actual clock rate.
281          */
282         serial_platform_data[0].uartclk = *(long *)XTFPGA_CLKFRQ_VADDR;
283
284
285         /* register platform devices */
286         platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
287
288         /* ETHOC driver is a bit quiet; at least display Ethernet MAC, so user
289          * knows whether they set it correctly on the DIP switches.
290          */
291         pr_info("XTFPGA: Ethernet MAC %pM\n", ethoc_pdata.hwaddr);
292
293         return 0;
294 }
295
296 /*
297  * Register to be done during do_initcalls().
298  */
299 arch_initcall(xtavnet_init);
300
301 #endif /* CONFIG_OF */