1/*-
2 * Copyright (c) 2009 Oleksandr Tymoshenko
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD$");
29
30#include "opt_ddb.h"
31#include "opt_ar71xx.h"
32
33#include <sys/param.h>
34#include <sys/conf.h>
35#include <sys/kernel.h>
36#include <sys/systm.h>
37#include <sys/bus.h>
38#include <sys/cons.h>
39#include <sys/kdb.h>
40#include <sys/reboot.h>
41
42#include <vm/vm.h>
43#include <vm/vm_page.h>
44
45#include <net/ethernet.h>
46
47#include <machine/clock.h>
48#include <machine/cpu.h>
49#include <machine/cpuregs.h>
50#include <machine/hwfunc.h>
51#include <machine/md_var.h>
52#include <machine/trap.h>
53#include <machine/vmparam.h>
54
55#include <mips/atheros/ar71xxreg.h>
56
57#include <mips/atheros/ar71xx_setup.h>
58#include <mips/atheros/ar71xx_cpudef.h>
59
60#include <mips/sentry5/s5reg.h>
61
62extern char edata[], end[];
63
64uint32_t ar711_base_mac[ETHER_ADDR_LEN];
65/* 4KB static data aread to keep a copy of the bootload env until
66   the dynamic kenv is setup */
67char boot1_env[4096];
68
69/*
70 * We get a string in from Redboot with the all the arguments together,
71 * "foo=bar bar=baz". Split them up and save in kenv.
72 */
73static void
74parse_argv(char *str)
75{
76	char *n, *v;
77
78	while ((v = strsep(&str, " ")) != NULL) {
79		if (*v == '\0')
80			continue;
81		if (*v == '-') {
82			while (*v != '\0') {
83				v++;
84				switch (*v) {
85				case 'a': boothowto |= RB_ASKNAME; break;
86				case 'd': boothowto |= RB_KDB; break;
87				case 'g': boothowto |= RB_GDB; break;
88				case 's': boothowto |= RB_SINGLE; break;
89				case 'v': boothowto |= RB_VERBOSE; break;
90				}
91			}
92		} else {
93			n = strsep(&v, "=");
94			if (v == NULL)
95				setenv(n, "1");
96			else
97				setenv(n, v);
98		}
99	}
100}
101
102void
103platform_cpu_init()
104{
105	/* Nothing special */
106}
107
108void
109platform_reset(void)
110{
111	ar71xx_device_stop(RST_RESET_FULL_CHIP);
112	/* Wait for reset */
113	while(1)
114		;
115}
116
117/*
118 * Obtain the MAC address via the Redboot environment.
119 */
120static void
121ar71xx_redboot_get_macaddr(void)
122{
123	char *var;
124	int count = 0;
125
126	/*
127	 * "ethaddr" is passed via envp on RedBoot platforms
128	 * "kmac" is passed via argv on RouterBOOT platforms
129	 */
130	if ((var = getenv("ethaddr")) != NULL ||
131	    (var = getenv("kmac")) != NULL) {
132		count = sscanf(var, "%x%*c%x%*c%x%*c%x%*c%x%*c%x",
133		    &ar711_base_mac[0], &ar711_base_mac[1],
134		    &ar711_base_mac[2], &ar711_base_mac[3],
135		    &ar711_base_mac[4], &ar711_base_mac[5]);
136		if (count < 6)
137			memset(ar711_base_mac, 0,
138			    sizeof(ar711_base_mac));
139		freeenv(var);
140	}
141}
142
143void
144platform_start(__register_t a0 __unused, __register_t a1 __unused,
145    __register_t a2 __unused, __register_t a3 __unused)
146{
147	uint64_t platform_counter_freq;
148	int argc = 0, i;
149	char **argv = NULL, **envp = NULL;
150	vm_offset_t kernend;
151
152	/*
153	 * clear the BSS and SBSS segments, this should be first call in
154	 * the function
155	 */
156	kernend = (vm_offset_t)&end;
157	memset(&edata, 0, kernend - (vm_offset_t)(&edata));
158
159	mips_postboot_fixup();
160
161	/* Initialize pcpu stuff */
162	mips_pcpu0_init();
163
164	/*
165	 * Until some more sensible abstractions for uboot/redboot
166	 * environment handling, we have to make this a compile-time
167	 * hack.  The existing code handles the uboot environment
168	 * very incorrectly so we should just ignore initialising
169	 * the relevant pointers.
170	 */
171#ifndef	AR71XX_ENV_UBOOT
172	argc = a0;
173	argv = (char**)a1;
174	envp = (char**)a2;
175#endif
176	/*
177	 * Protect ourselves from garbage in registers
178	 */
179	if (MIPS_IS_VALID_PTR(envp)) {
180		for (i = 0; envp[i]; i += 2) {
181			if (strcmp(envp[i], "memsize") == 0)
182				realmem = btoc(strtoul(envp[i+1], NULL, 16));
183		}
184	}
185
186	/*
187	 * Just wild guess. RedBoot let us down and didn't reported
188	 * memory size
189	 */
190	if (realmem == 0)
191		realmem = btoc(32*1024*1024);
192
193	/*
194	 * Allow build-time override in case Redboot lies
195	 * or in other situations (eg where there's u-boot)
196	 * where there isn't (yet) a convienent method of
197	 * being told how much RAM is available.
198	 *
199	 * This happens on at least the Ubiquiti LS-SR71A
200	 * board, where redboot says there's 16mb of RAM
201	 * but in fact there's 32mb.
202	 */
203#if	defined(AR71XX_REALMEM)
204		realmem = btoc(AR71XX_REALMEM);
205#endif
206
207	/* phys_avail regions are in bytes */
208	phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end);
209	phys_avail[1] = ctob(realmem);
210
211	dump_avail[0] = phys_avail[0];
212	dump_avail[1] = phys_avail[1] - phys_avail[0];
213
214	physmem = realmem;
215
216	/*
217	 * ns8250 uart code uses DELAY so ticker should be inititalized
218	 * before cninit. And tick_init_params refers to hz, so * init_param1
219	 * should be called first.
220	 */
221	init_param1();
222
223	/* Detect the system type - this is needed for subsequent chipset-specific calls */
224	ar71xx_detect_sys_type();
225	ar71xx_detect_sys_frequency();
226
227	platform_counter_freq = ar71xx_cpu_freq();
228	mips_timer_init_params(platform_counter_freq, 1);
229	cninit();
230	init_static_kenv(boot1_env, sizeof(boot1_env));
231
232	printf("CPU platform: %s\n", ar71xx_get_system_type());
233	printf("CPU Frequency=%d MHz\n", u_ar71xx_cpu_freq / 1000000);
234	printf("CPU DDR Frequency=%d MHz\n", u_ar71xx_ddr_freq / 1000000);
235	printf("CPU AHB Frequency=%d MHz\n", u_ar71xx_ahb_freq / 1000000);
236	printf("platform frequency: %lld\n", platform_counter_freq);
237	printf("CPU reference clock: %d MHz\n", u_ar71xx_refclk / 1000000);
238	printf("arguments: \n");
239	printf("  a0 = %08x\n", a0);
240	printf("  a1 = %08x\n", a1);
241	printf("  a2 = %08x\n", a2);
242	printf("  a3 = %08x\n", a3);
243
244	/*
245	 * XXX this code is very redboot specific.
246	 */
247	printf("Cmd line:");
248	if (MIPS_IS_VALID_PTR(argv)) {
249		for (i = 0; i < argc; i++) {
250			printf(" %s", argv[i]);
251			parse_argv(argv[i]);
252		}
253	}
254	else
255		printf ("argv is invalid");
256	printf("\n");
257
258	printf("Environment:\n");
259	if (MIPS_IS_VALID_PTR(envp)) {
260		for (i = 0; envp[i]; i+=2) {
261			printf("  %s = %s\n", envp[i], envp[i+1]);
262			setenv(envp[i], envp[i+1]);
263		}
264	}
265	else
266		printf ("envp is invalid\n");
267
268	/* Redboot if_arge MAC address is in the environment */
269	ar71xx_redboot_get_macaddr();
270
271	init_param2(physmem);
272	mips_cpu_init();
273	pmap_bootstrap();
274	mips_proc0_init();
275	mutex_init();
276
277	/*
278	 * Reset USB devices
279	 */
280	ar71xx_init_usb_peripheral();
281
282	kdb_init();
283#ifdef KDB
284	if (boothowto & RB_KDB)
285		kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger");
286#endif
287}
288