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 	of_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 	of_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 */
302