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
32#include <sys/param.h>
33#include <sys/conf.h>
34#include <sys/kernel.h>
35#include <sys/systm.h>
36#include <sys/bus.h>
37#include <sys/cons.h>
38#include <sys/kdb.h>
39#include <sys/reboot.h>
40
41#include <vm/vm.h>
42#include <vm/vm_page.h>
43
44#include <net/ethernet.h>
45
46#include <machine/clock.h>
47#include <machine/cpu.h>
48#include <machine/cpuregs.h>
49#include <machine/hwfunc.h>
50#include <machine/md_var.h>
51#include <machine/trap.h>
52#include <machine/vmparam.h>
53
54#include <mips/atheros/ar71xxreg.h>
55
56#include <mips/atheros/ar71xx_setup.h>
57#include <mips/atheros/ar71xx_cpudef.h>
58
59#include <mips/sentry5/s5reg.h>
60
61extern char edata[], end[];
62
63uint32_t ar711_base_mac[ETHER_ADDR_LEN];
64/* 4KB static data aread to keep a copy of the bootload env until
65   the dynamic kenv is setup */
66char boot1_env[4096];
67
68/*
69 * We get a string in from Redboot with the all the arguments together,
70 * "foo=bar bar=baz". Split them up and save in kenv.
71 */
72static void
73parse_argv(char *str)
74{
75	char *n, *v;
76
77	while ((v = strsep(&str, " ")) != NULL) {
78		if (*v == '\0')
79			continue;
80		if (*v == '-') {
81			while (*v != '\0') {
82				v++;
83				switch (*v) {
84				case 'a': boothowto |= RB_ASKNAME; break;
85				case 'd': boothowto |= RB_KDB; break;
86				case 'g': boothowto |= RB_GDB; break;
87				case 's': boothowto |= RB_SINGLE; break;
88				case 'v': boothowto |= RB_VERBOSE; break;
89				}
90			}
91		} else {
92			n = strsep(&v, "=");
93			if (v == NULL)
94				setenv(n, "1");
95			else
96				setenv(n, v);
97		}
98	}
99}
100
101void
102platform_cpu_init()
103{
104	/* Nothing special */
105}
106
107void
108platform_halt(void)
109{
110
111}
112
113void
114platform_identify(void)
115{
116
117}
118
119void
120platform_reset(void)
121{
122	ar71xx_device_stop(RST_RESET_FULL_CHIP);
123	/* Wait for reset */
124	while(1)
125		;
126}
127
128void
129platform_trap_enter(void)
130{
131
132}
133
134void
135platform_trap_exit(void)
136{
137
138}
139
140/*
141 * Obtain the MAC address via the Redboot environment.
142 */
143static void
144ar71xx_redboot_get_macaddr(void)
145{
146	char *var;
147	int count = 0;
148
149	/*
150	 * "ethaddr" is passed via envp on RedBoot platforms
151	 * "kmac" is passed via argv on RouterBOOT platforms
152	 */
153	if ((var = getenv("ethaddr")) != NULL ||
154	    (var = getenv("kmac")) != NULL) {
155		count = sscanf(var, "%x%*c%x%*c%x%*c%x%*c%x%*c%x",
156		    &ar711_base_mac[0], &ar711_base_mac[1],
157		    &ar711_base_mac[2], &ar711_base_mac[3],
158		    &ar711_base_mac[4], &ar711_base_mac[5]);
159		if (count < 6)
160			memset(ar711_base_mac, 0,
161			    sizeof(ar711_base_mac));
162		freeenv(var);
163	}
164}
165
166void
167platform_start(__register_t a0 __unused, __register_t a1 __unused,
168    __register_t a2 __unused, __register_t a3 __unused)
169{
170	uint64_t platform_counter_freq;
171	int argc, i;
172	char **argv, **envp;
173	vm_offset_t kernend;
174
175	/*
176	 * clear the BSS and SBSS segments, this should be first call in
177	 * the function
178	 */
179	kernend = (vm_offset_t)&end;
180	memset(&edata, 0, kernend - (vm_offset_t)(&edata));
181
182	mips_postboot_fixup();
183
184	/* Initialize pcpu stuff */
185	mips_pcpu0_init();
186
187	argc = a0;
188	argv = (char**)a1;
189	envp = (char**)a2;
190	/*
191	 * Protect ourselves from garbage in registers
192	 */
193	if (MIPS_IS_VALID_PTR(envp)) {
194		for (i = 0; envp[i]; i += 2) {
195			if (strcmp(envp[i], "memsize") == 0)
196				realmem = btoc(strtoul(envp[i+1], NULL, 16));
197		}
198	}
199
200	/*
201	 * Just wild guess. RedBoot let us down and didn't reported
202	 * memory size
203	 */
204	if (realmem == 0)
205		realmem = btoc(32*1024*1024);
206
207	/*
208	 * Allow build-time override in case Redboot lies
209	 * or in other situations (eg where there's u-boot)
210	 * where there isn't (yet) a convienent method of
211	 * being told how much RAM is available.
212	 *
213	 * This happens on at least the Ubiquiti LS-SR71A
214	 * board, where redboot says there's 16mb of RAM
215	 * but in fact there's 32mb.
216	 */
217#if	defined(AR71XX_REALMEM)
218		realmem = btoc(AR71XX_REALMEM);
219#endif
220
221	/* phys_avail regions are in bytes */
222	phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end);
223	phys_avail[1] = ctob(realmem);
224
225	dump_avail[0] = phys_avail[0];
226	dump_avail[1] = phys_avail[1] - phys_avail[0];
227
228	physmem = realmem;
229
230	/*
231	 * ns8250 uart code uses DELAY so ticker should be inititalized
232	 * before cninit. And tick_init_params refers to hz, so * init_param1
233	 * should be called first.
234	 */
235	init_param1();
236
237	/* Detect the system type - this is needed for subsequent chipset-specific calls */
238	ar71xx_detect_sys_type();
239	ar71xx_detect_sys_frequency();
240
241	platform_counter_freq = ar71xx_cpu_freq();
242	mips_timer_init_params(platform_counter_freq, 1);
243	cninit();
244	init_static_kenv(boot1_env, sizeof(boot1_env));
245
246	printf("CPU platform: %s\n", ar71xx_get_system_type());
247	printf("CPU Frequency=%d MHz\n", u_ar71xx_cpu_freq / 1000000);
248	printf("CPU DDR Frequency=%d MHz\n", u_ar71xx_ddr_freq / 1000000);
249	printf("CPU AHB Frequency=%d MHz\n", u_ar71xx_ahb_freq / 1000000);
250
251	printf("platform frequency: %lld\n", platform_counter_freq);
252	printf("arguments: \n");
253	printf("  a0 = %08x\n", a0);
254	printf("  a1 = %08x\n", a1);
255	printf("  a2 = %08x\n", a2);
256	printf("  a3 = %08x\n", a3);
257
258	printf("Cmd line:");
259	if (MIPS_IS_VALID_PTR(argv)) {
260		for (i = 0; i < argc; i++) {
261			printf(" %s", argv[i]);
262			parse_argv(argv[i]);
263		}
264	}
265	else
266		printf ("argv is invalid");
267	printf("\n");
268
269	printf("Environment:\n");
270	if (MIPS_IS_VALID_PTR(envp)) {
271		for (i = 0; envp[i]; i+=2) {
272			printf("  %s = %s\n", envp[i], envp[i+1]);
273			setenv(envp[i], envp[i+1]);
274		}
275	}
276	else
277		printf ("envp is invalid\n");
278
279	/* Redboot if_arge MAC address is in the environment */
280	ar71xx_redboot_get_macaddr();
281
282	init_param2(physmem);
283	mips_cpu_init();
284	pmap_bootstrap();
285	mips_proc0_init();
286	mutex_init();
287
288	/*
289	 * Reset USB devices
290	 */
291	ar71xx_init_usb_peripheral();
292
293	kdb_init();
294#ifdef KDB
295	if (boothowto & RB_KDB)
296		kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger");
297#endif
298}
299