1187423Sgonzo/*-
2187423Sgonzo * Copyright (c) 2009 Oleksandr Tymoshenko
3187423Sgonzo * All rights reserved.
4187423Sgonzo *
5187423Sgonzo * Redistribution and use in source and binary forms, with or without
6187423Sgonzo * modification, are permitted provided that the following conditions
7187423Sgonzo * are met:
8187423Sgonzo * 1. Redistributions of source code must retain the above copyright
9187423Sgonzo *    notice, this list of conditions and the following disclaimer.
10187423Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
11187423Sgonzo *    notice, this list of conditions and the following disclaimer in the
12187423Sgonzo *    documentation and/or other materials provided with the distribution.
13187423Sgonzo *
14187423Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15187423Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16187423Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17187423Sgonzo * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18187423Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19187423Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20187423Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21187423Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22187423Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23187423Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24187423Sgonzo * SUCH DAMAGE.
25187423Sgonzo */
26187423Sgonzo
27187423Sgonzo#include <sys/cdefs.h>
28187423Sgonzo__FBSDID("$FreeBSD$");
29187423Sgonzo
30187423Sgonzo#include "opt_ddb.h"
31187423Sgonzo
32187423Sgonzo#include <sys/param.h>
33187423Sgonzo#include <sys/conf.h>
34187423Sgonzo#include <sys/kernel.h>
35187423Sgonzo#include <sys/systm.h>
36187423Sgonzo#include <sys/bus.h>
37187423Sgonzo#include <sys/cons.h>
38187423Sgonzo#include <sys/kdb.h>
39198562Sthompsa#include <sys/reboot.h>
40187423Sgonzo
41187423Sgonzo#include <vm/vm.h>
42187423Sgonzo#include <vm/vm_page.h>
43187423Sgonzo
44192178Sgonzo#include <net/ethernet.h>
45192178Sgonzo
46187423Sgonzo#include <machine/clock.h>
47187423Sgonzo#include <machine/cpu.h>
48223562Skevlo#include <machine/cpuregs.h>
49187423Sgonzo#include <machine/hwfunc.h>
50187423Sgonzo#include <machine/md_var.h>
51187423Sgonzo#include <machine/trap.h>
52187423Sgonzo#include <machine/vmparam.h>
53187423Sgonzo
54187456Sgonzo#include <mips/atheros/ar71xxreg.h>
55187423Sgonzo
56211476Sadrian#include <mips/atheros/ar71xx_setup.h>
57211476Sadrian#include <mips/atheros/ar71xx_cpudef.h>
58211476Sadrian
59223562Skevlo#include <mips/sentry5/s5reg.h>
60223562Skevlo
61202954Sgonzoextern char edata[], end[];
62202954Sgonzo
63192178Sgonzouint32_t ar711_base_mac[ETHER_ADDR_LEN];
64198562Sthompsa/* 4KB static data aread to keep a copy of the bootload env until
65198562Sthompsa   the dynamic kenv is setup */
66198562Sthompsachar boot1_env[4096];
67187423Sgonzo
68198562Sthompsa/*
69198562Sthompsa * We get a string in from Redboot with the all the arguments together,
70198562Sthompsa * "foo=bar bar=baz". Split them up and save in kenv.
71198562Sthompsa */
72198562Sthompsastatic void
73198562Sthompsaparse_argv(char *str)
74198562Sthompsa{
75198562Sthompsa	char *n, *v;
76198562Sthompsa
77198562Sthompsa	while ((v = strsep(&str, " ")) != NULL) {
78198562Sthompsa		if (*v == '\0')
79198562Sthompsa			continue;
80198562Sthompsa		if (*v == '-') {
81198562Sthompsa			while (*v != '\0') {
82198562Sthompsa				v++;
83198562Sthompsa				switch (*v) {
84198562Sthompsa				case 'a': boothowto |= RB_ASKNAME; break;
85198562Sthompsa				case 'd': boothowto |= RB_KDB; break;
86198562Sthompsa				case 'g': boothowto |= RB_GDB; break;
87198562Sthompsa				case 's': boothowto |= RB_SINGLE; break;
88198562Sthompsa				case 'v': boothowto |= RB_VERBOSE; break;
89198562Sthompsa				}
90198562Sthompsa			}
91198562Sthompsa		} else {
92198562Sthompsa			n = strsep(&v, "=");
93198562Sthompsa			if (v == NULL)
94198562Sthompsa				setenv(n, "1");
95198562Sthompsa			else
96198562Sthompsa				setenv(n, v);
97198562Sthompsa		}
98198562Sthompsa	}
99198562Sthompsa}
100198562Sthompsa
101187423Sgonzovoid
102198669Srrsplatform_cpu_init()
103198669Srrs{
104198669Srrs	/* Nothing special */
105198669Srrs}
106198669Srrs
107198669Srrsvoid
108187423Sgonzoplatform_halt(void)
109187423Sgonzo{
110187423Sgonzo
111187423Sgonzo}
112187423Sgonzo
113187423Sgonzovoid
114187423Sgonzoplatform_identify(void)
115187423Sgonzo{
116187423Sgonzo
117187423Sgonzo}
118187423Sgonzo
119187423Sgonzovoid
120187423Sgonzoplatform_reset(void)
121187423Sgonzo{
122211480Sadrian	ar71xx_device_stop(RST_RESET_FULL_CHIP);
123187463Sgonzo	/* Wait for reset */
124187463Sgonzo	while(1)
125187463Sgonzo		;
126187423Sgonzo}
127187423Sgonzo
128187423Sgonzovoid
129187423Sgonzoplatform_trap_enter(void)
130187423Sgonzo{
131187423Sgonzo
132187423Sgonzo}
133187423Sgonzo
134187423Sgonzovoid
135187423Sgonzoplatform_trap_exit(void)
136187423Sgonzo{
137187423Sgonzo
138187423Sgonzo}
139187423Sgonzo
140220056Sadrian/*
141220056Sadrian * Obtain the MAC address via the Redboot environment.
142220056Sadrian */
143220056Sadrianstatic void
144220056Sadrianar71xx_redboot_get_macaddr(void)
145220056Sadrian{
146220056Sadrian	char *var;
147220056Sadrian	int count = 0;
148220056Sadrian
149220056Sadrian	/*
150220056Sadrian	 * "ethaddr" is passed via envp on RedBoot platforms
151220056Sadrian	 * "kmac" is passed via argv on RouterBOOT platforms
152220056Sadrian	 */
153220056Sadrian	if ((var = getenv("ethaddr")) != NULL ||
154220056Sadrian	    (var = getenv("kmac")) != NULL) {
155220056Sadrian		count = sscanf(var, "%x%*c%x%*c%x%*c%x%*c%x%*c%x",
156220056Sadrian		    &ar711_base_mac[0], &ar711_base_mac[1],
157220056Sadrian		    &ar711_base_mac[2], &ar711_base_mac[3],
158220056Sadrian		    &ar711_base_mac[4], &ar711_base_mac[5]);
159220056Sadrian		if (count < 6)
160220056Sadrian			memset(ar711_base_mac, 0,
161220056Sadrian			    sizeof(ar711_base_mac));
162220056Sadrian		freeenv(var);
163220056Sadrian	}
164220056Sadrian}
165220056Sadrian
166187423Sgonzovoid
167187423Sgonzoplatform_start(__register_t a0 __unused, __register_t a1 __unused,
168187423Sgonzo    __register_t a2 __unused, __register_t a3 __unused)
169187423Sgonzo{
170195513Sgonzo	uint64_t platform_counter_freq;
171220056Sadrian	int argc, i;
172220056Sadrian	char **argv, **envp;
173202954Sgonzo	vm_offset_t kernend;
174187423Sgonzo
175202954Sgonzo	/*
176202954Sgonzo	 * clear the BSS and SBSS segments, this should be first call in
177202954Sgonzo	 * the function
178202954Sgonzo	 */
179202954Sgonzo	kernend = (vm_offset_t)&end;
180187423Sgonzo	memset(&edata, 0, kernend - (vm_offset_t)(&edata));
181187423Sgonzo
182202954Sgonzo	mips_postboot_fixup();
183202954Sgonzo
184201845Simp	/* Initialize pcpu stuff */
185201881Simp	mips_pcpu0_init();
186201845Simp
187192178Sgonzo	argc = a0;
188192178Sgonzo	argv = (char**)a1;
189192178Sgonzo	envp = (char**)a2;
190192178Sgonzo	/*
191192178Sgonzo	 * Protect ourselves from garbage in registers
192192178Sgonzo	 */
193192178Sgonzo	if (MIPS_IS_VALID_PTR(envp)) {
194212774Sthompsa		for (i = 0; envp[i]; i += 2) {
195192178Sgonzo			if (strcmp(envp[i], "memsize") == 0)
196192178Sgonzo				realmem = btoc(strtoul(envp[i+1], NULL, 16));
197192178Sgonzo		}
198192178Sgonzo	}
199192178Sgonzo
200192178Sgonzo	/*
201192178Sgonzo	 * Just wild guess. RedBoot let us down and didn't reported
202192178Sgonzo	 * memory size
203192178Sgonzo	 */
204192178Sgonzo	if (realmem == 0)
205192178Sgonzo		realmem = btoc(32*1024*1024);
206192178Sgonzo
207220052Sadrian	/*
208220052Sadrian	 * Allow build-time override in case Redboot lies
209220052Sadrian	 * or in other situations (eg where there's u-boot)
210220052Sadrian	 * where there isn't (yet) a convienent method of
211220052Sadrian	 * being told how much RAM is available.
212220052Sadrian	 *
213220052Sadrian	 * This happens on at least the Ubiquiti LS-SR71A
214220052Sadrian	 * board, where redboot says there's 16mb of RAM
215220052Sadrian	 * but in fact there's 32mb.
216220052Sadrian	 */
217220052Sadrian#if	defined(AR71XX_REALMEM)
218220096Sadrian		realmem = btoc(AR71XX_REALMEM);
219220052Sadrian#endif
220220052Sadrian
221187424Sgonzo	/* phys_avail regions are in bytes */
222202954Sgonzo	phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end);
223187424Sgonzo	phys_avail[1] = ctob(realmem);
224187423Sgonzo
225216318Sgonzo	dump_avail[0] = phys_avail[0];
226216318Sgonzo	dump_avail[1] = phys_avail[1] - phys_avail[0];
227216318Sgonzo
228187424Sgonzo	physmem = realmem;
229187423Sgonzo
230187423Sgonzo	/*
231187424Sgonzo	 * ns8250 uart code uses DELAY so ticker should be inititalized
232187424Sgonzo	 * before cninit. And tick_init_params refers to hz, so * init_param1
233187424Sgonzo	 * should be called first.
234187424Sgonzo	 */
235187424Sgonzo	init_param1();
236211476Sadrian
237211476Sadrian	/* Detect the system type - this is needed for subsequent chipset-specific calls */
238211476Sadrian	ar71xx_detect_sys_type();
239211476Sadrian	ar71xx_detect_sys_frequency();
240211476Sadrian
241195513Sgonzo	platform_counter_freq = ar71xx_cpu_freq();
242192365Sgonzo	mips_timer_init_params(platform_counter_freq, 1);
243187424Sgonzo	cninit();
244198562Sthompsa	init_static_kenv(boot1_env, sizeof(boot1_env));
245187423Sgonzo
246211476Sadrian	printf("CPU platform: %s\n", ar71xx_get_system_type());
247211476Sadrian	printf("CPU Frequency=%d MHz\n", u_ar71xx_cpu_freq / 1000000);
248211476Sadrian	printf("CPU DDR Frequency=%d MHz\n", u_ar71xx_ddr_freq / 1000000);
249211476Sadrian	printf("CPU AHB Frequency=%d MHz\n", u_ar71xx_ahb_freq / 1000000);
250211476Sadrian
251192132Sgonzo	printf("platform frequency: %lld\n", platform_counter_freq);
252187424Sgonzo	printf("arguments: \n");
253187423Sgonzo	printf("  a0 = %08x\n", a0);
254187423Sgonzo	printf("  a1 = %08x\n", a1);
255187423Sgonzo	printf("  a2 = %08x\n", a2);
256187423Sgonzo	printf("  a3 = %08x\n", a3);
257187423Sgonzo
258192178Sgonzo	printf("Cmd line:");
259192178Sgonzo	if (MIPS_IS_VALID_PTR(argv)) {
260198562Sthompsa		for (i = 0; i < argc; i++) {
261192178Sgonzo			printf(" %s", argv[i]);
262198562Sthompsa			parse_argv(argv[i]);
263198562Sthompsa		}
264192178Sgonzo	}
265192178Sgonzo	else
266192178Sgonzo		printf ("argv is invalid");
267192178Sgonzo	printf("\n");
268192178Sgonzo
269192178Sgonzo	printf("Environment:\n");
270192178Sgonzo	if (MIPS_IS_VALID_PTR(envp)) {
271198562Sthompsa		for (i = 0; envp[i]; i+=2) {
272192178Sgonzo			printf("  %s = %s\n", envp[i], envp[i+1]);
273198562Sthompsa			setenv(envp[i], envp[i+1]);
274198562Sthompsa		}
275192178Sgonzo	}
276192178Sgonzo	else
277192178Sgonzo		printf ("envp is invalid\n");
278192178Sgonzo
279220056Sadrian	/* Redboot if_arge MAC address is in the environment */
280220056Sadrian	ar71xx_redboot_get_macaddr();
281212774Sthompsa
282187424Sgonzo	init_param2(physmem);
283187424Sgonzo	mips_cpu_init();
284187424Sgonzo	pmap_bootstrap();
285187424Sgonzo	mips_proc0_init();
286187424Sgonzo	mutex_init();
287187423Sgonzo
288188882Sgonzo	/*
289188882Sgonzo	 * Reset USB devices
290188882Sgonzo	 */
291211481Sadrian	ar71xx_init_usb_peripheral();
292188882Sgonzo
293187424Sgonzo	kdb_init();
294202849Simp#ifdef KDB
295202849Simp	if (boothowto & RB_KDB)
296202849Simp		kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger");
297187423Sgonzo#endif
298187423Sgonzo}
299