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"
31230195Sadrian#include "opt_ar71xx.h"
32187423Sgonzo
33187423Sgonzo#include <sys/param.h>
34187423Sgonzo#include <sys/conf.h>
35187423Sgonzo#include <sys/kernel.h>
36187423Sgonzo#include <sys/systm.h>
37187423Sgonzo#include <sys/bus.h>
38187423Sgonzo#include <sys/cons.h>
39187423Sgonzo#include <sys/kdb.h>
40198562Sthompsa#include <sys/reboot.h>
41187423Sgonzo
42187423Sgonzo#include <vm/vm.h>
43187423Sgonzo#include <vm/vm_page.h>
44187423Sgonzo
45192178Sgonzo#include <net/ethernet.h>
46192178Sgonzo
47187423Sgonzo#include <machine/clock.h>
48187423Sgonzo#include <machine/cpu.h>
49223562Skevlo#include <machine/cpuregs.h>
50187423Sgonzo#include <machine/hwfunc.h>
51187423Sgonzo#include <machine/md_var.h>
52187423Sgonzo#include <machine/trap.h>
53187423Sgonzo#include <machine/vmparam.h>
54187423Sgonzo
55187456Sgonzo#include <mips/atheros/ar71xxreg.h>
56187423Sgonzo
57211476Sadrian#include <mips/atheros/ar71xx_setup.h>
58211476Sadrian#include <mips/atheros/ar71xx_cpudef.h>
59211476Sadrian
60223562Skevlo#include <mips/sentry5/s5reg.h>
61223562Skevlo
62202954Sgonzoextern char edata[], end[];
63202954Sgonzo
64192178Sgonzouint32_t ar711_base_mac[ETHER_ADDR_LEN];
65198562Sthompsa/* 4KB static data aread to keep a copy of the bootload env until
66198562Sthompsa   the dynamic kenv is setup */
67198562Sthompsachar boot1_env[4096];
68187423Sgonzo
69198562Sthompsa/*
70198562Sthompsa * We get a string in from Redboot with the all the arguments together,
71198562Sthompsa * "foo=bar bar=baz". Split them up and save in kenv.
72198562Sthompsa */
73198562Sthompsastatic void
74198562Sthompsaparse_argv(char *str)
75198562Sthompsa{
76198562Sthompsa	char *n, *v;
77198562Sthompsa
78198562Sthompsa	while ((v = strsep(&str, " ")) != NULL) {
79198562Sthompsa		if (*v == '\0')
80198562Sthompsa			continue;
81198562Sthompsa		if (*v == '-') {
82198562Sthompsa			while (*v != '\0') {
83198562Sthompsa				v++;
84198562Sthompsa				switch (*v) {
85198562Sthompsa				case 'a': boothowto |= RB_ASKNAME; break;
86198562Sthompsa				case 'd': boothowto |= RB_KDB; break;
87198562Sthompsa				case 'g': boothowto |= RB_GDB; break;
88198562Sthompsa				case 's': boothowto |= RB_SINGLE; break;
89198562Sthompsa				case 'v': boothowto |= RB_VERBOSE; break;
90198562Sthompsa				}
91198562Sthompsa			}
92198562Sthompsa		} else {
93198562Sthompsa			n = strsep(&v, "=");
94198562Sthompsa			if (v == NULL)
95198562Sthompsa				setenv(n, "1");
96198562Sthompsa			else
97198562Sthompsa				setenv(n, v);
98198562Sthompsa		}
99198562Sthompsa	}
100198562Sthompsa}
101198562Sthompsa
102187423Sgonzovoid
103198669Srrsplatform_cpu_init()
104198669Srrs{
105198669Srrs	/* Nothing special */
106198669Srrs}
107198669Srrs
108198669Srrsvoid
109187423Sgonzoplatform_reset(void)
110187423Sgonzo{
111211480Sadrian	ar71xx_device_stop(RST_RESET_FULL_CHIP);
112187463Sgonzo	/* Wait for reset */
113187463Sgonzo	while(1)
114187463Sgonzo		;
115187423Sgonzo}
116187423Sgonzo
117220056Sadrian/*
118220056Sadrian * Obtain the MAC address via the Redboot environment.
119220056Sadrian */
120220056Sadrianstatic void
121220056Sadrianar71xx_redboot_get_macaddr(void)
122220056Sadrian{
123220056Sadrian	char *var;
124220056Sadrian	int count = 0;
125220056Sadrian
126220056Sadrian	/*
127220056Sadrian	 * "ethaddr" is passed via envp on RedBoot platforms
128220056Sadrian	 * "kmac" is passed via argv on RouterBOOT platforms
129220056Sadrian	 */
130220056Sadrian	if ((var = getenv("ethaddr")) != NULL ||
131220056Sadrian	    (var = getenv("kmac")) != NULL) {
132220056Sadrian		count = sscanf(var, "%x%*c%x%*c%x%*c%x%*c%x%*c%x",
133220056Sadrian		    &ar711_base_mac[0], &ar711_base_mac[1],
134220056Sadrian		    &ar711_base_mac[2], &ar711_base_mac[3],
135220056Sadrian		    &ar711_base_mac[4], &ar711_base_mac[5]);
136220056Sadrian		if (count < 6)
137220056Sadrian			memset(ar711_base_mac, 0,
138220056Sadrian			    sizeof(ar711_base_mac));
139220056Sadrian		freeenv(var);
140220056Sadrian	}
141220056Sadrian}
142220056Sadrian
143187423Sgonzovoid
144187423Sgonzoplatform_start(__register_t a0 __unused, __register_t a1 __unused,
145187423Sgonzo    __register_t a2 __unused, __register_t a3 __unused)
146187423Sgonzo{
147195513Sgonzo	uint64_t platform_counter_freq;
148227924Sadrian	int argc = 0, i;
149227924Sadrian	char **argv = NULL, **envp = NULL;
150202954Sgonzo	vm_offset_t kernend;
151187423Sgonzo
152202954Sgonzo	/*
153202954Sgonzo	 * clear the BSS and SBSS segments, this should be first call in
154202954Sgonzo	 * the function
155202954Sgonzo	 */
156202954Sgonzo	kernend = (vm_offset_t)&end;
157187423Sgonzo	memset(&edata, 0, kernend - (vm_offset_t)(&edata));
158187423Sgonzo
159202954Sgonzo	mips_postboot_fixup();
160202954Sgonzo
161201845Simp	/* Initialize pcpu stuff */
162201881Simp	mips_pcpu0_init();
163201845Simp
164227924Sadrian	/*
165227924Sadrian	 * Until some more sensible abstractions for uboot/redboot
166227924Sadrian	 * environment handling, we have to make this a compile-time
167227924Sadrian	 * hack.  The existing code handles the uboot environment
168227924Sadrian	 * very incorrectly so we should just ignore initialising
169227924Sadrian	 * the relevant pointers.
170227924Sadrian	 */
171227924Sadrian#ifndef	AR71XX_ENV_UBOOT
172192178Sgonzo	argc = a0;
173192178Sgonzo	argv = (char**)a1;
174192178Sgonzo	envp = (char**)a2;
175227924Sadrian#endif
176192178Sgonzo	/*
177192178Sgonzo	 * Protect ourselves from garbage in registers
178192178Sgonzo	 */
179192178Sgonzo	if (MIPS_IS_VALID_PTR(envp)) {
180212774Sthompsa		for (i = 0; envp[i]; i += 2) {
181192178Sgonzo			if (strcmp(envp[i], "memsize") == 0)
182192178Sgonzo				realmem = btoc(strtoul(envp[i+1], NULL, 16));
183192178Sgonzo		}
184192178Sgonzo	}
185192178Sgonzo
186192178Sgonzo	/*
187192178Sgonzo	 * Just wild guess. RedBoot let us down and didn't reported
188192178Sgonzo	 * memory size
189192178Sgonzo	 */
190192178Sgonzo	if (realmem == 0)
191192178Sgonzo		realmem = btoc(32*1024*1024);
192192178Sgonzo
193220052Sadrian	/*
194220052Sadrian	 * Allow build-time override in case Redboot lies
195220052Sadrian	 * or in other situations (eg where there's u-boot)
196220052Sadrian	 * where there isn't (yet) a convienent method of
197220052Sadrian	 * being told how much RAM is available.
198220052Sadrian	 *
199220052Sadrian	 * This happens on at least the Ubiquiti LS-SR71A
200220052Sadrian	 * board, where redboot says there's 16mb of RAM
201220052Sadrian	 * but in fact there's 32mb.
202220052Sadrian	 */
203220052Sadrian#if	defined(AR71XX_REALMEM)
204220096Sadrian		realmem = btoc(AR71XX_REALMEM);
205220052Sadrian#endif
206220052Sadrian
207187424Sgonzo	/* phys_avail regions are in bytes */
208202954Sgonzo	phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end);
209187424Sgonzo	phys_avail[1] = ctob(realmem);
210187423Sgonzo
211216318Sgonzo	dump_avail[0] = phys_avail[0];
212216318Sgonzo	dump_avail[1] = phys_avail[1] - phys_avail[0];
213216318Sgonzo
214187424Sgonzo	physmem = realmem;
215187423Sgonzo
216187423Sgonzo	/*
217187424Sgonzo	 * ns8250 uart code uses DELAY so ticker should be inititalized
218187424Sgonzo	 * before cninit. And tick_init_params refers to hz, so * init_param1
219187424Sgonzo	 * should be called first.
220187424Sgonzo	 */
221187424Sgonzo	init_param1();
222211476Sadrian
223211476Sadrian	/* Detect the system type - this is needed for subsequent chipset-specific calls */
224211476Sadrian	ar71xx_detect_sys_type();
225211476Sadrian	ar71xx_detect_sys_frequency();
226211476Sadrian
227195513Sgonzo	platform_counter_freq = ar71xx_cpu_freq();
228192365Sgonzo	mips_timer_init_params(platform_counter_freq, 1);
229187424Sgonzo	cninit();
230198562Sthompsa	init_static_kenv(boot1_env, sizeof(boot1_env));
231187423Sgonzo
232211476Sadrian	printf("CPU platform: %s\n", ar71xx_get_system_type());
233211476Sadrian	printf("CPU Frequency=%d MHz\n", u_ar71xx_cpu_freq / 1000000);
234211476Sadrian	printf("CPU DDR Frequency=%d MHz\n", u_ar71xx_ddr_freq / 1000000);
235248865Sadrian	printf("CPU AHB Frequency=%d MHz\n", u_ar71xx_ahb_freq / 1000000);
236192132Sgonzo	printf("platform frequency: %lld\n", platform_counter_freq);
237248865Sadrian	printf("CPU reference clock: %d MHz\n", u_ar71xx_refclk / 1000000);
238187424Sgonzo	printf("arguments: \n");
239187423Sgonzo	printf("  a0 = %08x\n", a0);
240187423Sgonzo	printf("  a1 = %08x\n", a1);
241187423Sgonzo	printf("  a2 = %08x\n", a2);
242187423Sgonzo	printf("  a3 = %08x\n", a3);
243187423Sgonzo
244227924Sadrian	/*
245227924Sadrian	 * XXX this code is very redboot specific.
246227924Sadrian	 */
247192178Sgonzo	printf("Cmd line:");
248192178Sgonzo	if (MIPS_IS_VALID_PTR(argv)) {
249198562Sthompsa		for (i = 0; i < argc; i++) {
250192178Sgonzo			printf(" %s", argv[i]);
251198562Sthompsa			parse_argv(argv[i]);
252198562Sthompsa		}
253192178Sgonzo	}
254192178Sgonzo	else
255192178Sgonzo		printf ("argv is invalid");
256192178Sgonzo	printf("\n");
257192178Sgonzo
258192178Sgonzo	printf("Environment:\n");
259192178Sgonzo	if (MIPS_IS_VALID_PTR(envp)) {
260198562Sthompsa		for (i = 0; envp[i]; i+=2) {
261192178Sgonzo			printf("  %s = %s\n", envp[i], envp[i+1]);
262198562Sthompsa			setenv(envp[i], envp[i+1]);
263198562Sthompsa		}
264192178Sgonzo	}
265192178Sgonzo	else
266192178Sgonzo		printf ("envp is invalid\n");
267192178Sgonzo
268220056Sadrian	/* Redboot if_arge MAC address is in the environment */
269220056Sadrian	ar71xx_redboot_get_macaddr();
270212774Sthompsa
271187424Sgonzo	init_param2(physmem);
272187424Sgonzo	mips_cpu_init();
273187424Sgonzo	pmap_bootstrap();
274187424Sgonzo	mips_proc0_init();
275187424Sgonzo	mutex_init();
276187423Sgonzo
277188882Sgonzo	/*
278188882Sgonzo	 * Reset USB devices
279188882Sgonzo	 */
280211481Sadrian	ar71xx_init_usb_peripheral();
281188882Sgonzo
282187424Sgonzo	kdb_init();
283202849Simp#ifdef KDB
284202849Simp	if (boothowto & RB_KDB)
285202849Simp		kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger");
286187423Sgonzo#endif
287187423Sgonzo}
288