1/*-
2 * Copyright (c) 2007 Bruce M. Simpson.
3 * Copyright (c) 2016 Michael Zhilin <mizhka@gmail.com>
4 * Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
5 * Copyright (c) 2017 The FreeBSD Foundation
6 * All rights reserved.
7 *
8 * Portions of this software were developed by Landon Fuller
9 * under sponsorship from the FreeBSD Foundation.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD$");
35
36#include "opt_ddb.h"
37
38#include <sys/param.h>
39#include <sys/conf.h>
40#include <sys/kernel.h>
41#include <sys/systm.h>
42#include <sys/imgact.h>
43#include <sys/bio.h>
44#include <sys/buf.h>
45#include <sys/bus.h>
46#include <sys/cpu.h>
47#include <sys/cons.h>
48#include <sys/exec.h>
49#include <sys/ucontext.h>
50#include <sys/proc.h>
51#include <sys/kdb.h>
52#include <sys/ptrace.h>
53#include <sys/reboot.h>
54#include <sys/signalvar.h>
55#include <sys/sysent.h>
56#include <sys/sysproto.h>
57#include <sys/user.h>
58
59#include <vm/vm.h>
60#include <vm/vm_object.h>
61#include <vm/vm_page.h>
62
63#include <machine/cache.h>
64#include <machine/clock.h>
65#include <machine/cpu.h>
66#include <machine/cpuinfo.h>
67#include <machine/cpufunc.h>
68#include <machine/cpuregs.h>
69#include <machine/hwfunc.h>
70#include <machine/intr_machdep.h>
71#include <machine/locore.h>
72#include <machine/md_var.h>
73#include <machine/pte.h>
74#include <machine/sigframe.h>
75#include <machine/trap.h>
76#include <machine/vmparam.h>
77
78#include <dev/bhnd/bhnd.h>
79#include <dev/bhnd/bhndreg.h>
80#include <dev/bhnd/bhnd_eromvar.h>
81
82#include <dev/bhnd/bcma/bcma_eromvar.h>
83
84#include <dev/bhnd/siba/sibareg.h>
85#include <dev/bhnd/siba/sibavar.h>
86
87#include <dev/bhnd/cores/chipc/chipcreg.h>
88#include <dev/bhnd/cores/pmu/bhnd_pmureg.h>
89
90#include "bcm_machdep.h"
91#include "bcm_bmips_exts.h"
92
93#ifdef CFE
94#include <dev/cfe/cfe_api.h>
95#include <dev/cfe/cfe_error.h>
96#endif
97
98#if 0
99#define	BCM_TRACE(_fmt, ...)	printf(_fmt, ##__VA_ARGS__)
100#else
101#define	BCM_TRACE(_fmt, ...)
102#endif
103
104static int	bcm_init_platform_data(struct bcm_platform *bp);
105
106static int	bcm_find_core(struct bcm_platform *bp,
107		    const struct bhnd_core_match *descs, size_t num_descs,
108		    struct bhnd_core_info *info, uintptr_t *addr);
109
110static int	bcm_erom_probe_and_attach(bhnd_erom_class_t **erom_cls,
111		    kobj_ops_t erom_ops, bhnd_erom_t *erom, size_t esize,
112		    struct bhnd_erom_io *eio, struct bhnd_chipid *cid);
113
114extern int	*edata;
115extern int	*end;
116
117static struct bcm_platform	 bcm_platform_data;
118static bool			 bcm_platform_data_avail = false;
119
120#ifdef CFE
121static struct bcm_nvram_iocfe	 bcm_cfe_nvram;
122#endif
123
124static const struct bhnd_core_match bcm_chipc_cores[] = {
125	{ BHND_MATCH_CORE(BHND_MFGID_BCM,	BHND_COREID_CC)		},
126	{ BHND_MATCH_CORE(BHND_MFGID_BCM,	BHND_COREID_4706_CC)	},
127};
128
129static const struct bhnd_core_match bcm_cpu0_cores[] = {
130	{
131		BHND_MATCH_CORE_CLASS(BHND_DEVCLASS_CPU),
132		BHND_MATCH_CORE_UNIT(0)
133	}
134};
135
136static const struct bhnd_core_match bcm_pmu_cores[] = {
137	{ BHND_MATCH_CORE(BHND_MFGID_BCM,	BHND_COREID_PMU)	},
138};
139
140struct bcm_platform *
141bcm_get_platform(void)
142{
143	if (!bcm_platform_data_avail)
144		panic("platform data not available");
145
146	return (&bcm_platform_data);
147}
148
149static bus_addr_t
150bcm_get_bus_addr(void)
151{
152	long maddr;
153
154	if (resource_long_value("bhnd", 0, "maddr", &maddr) == 0)
155		return ((u_long)maddr);
156
157	return (BHND_DEFAULT_CHIPC_ADDR);
158}
159
160static bus_size_t
161bcm_get_bus_size(void)
162{
163	long msize;
164
165	if (resource_long_value("bhnd", 0, "msize", &msize) == 0)
166		return ((u_long)msize);
167
168	return (BHND_DEFAULT_ENUM_SIZE);
169}
170
171/**
172 * Search the device enumeration table for a core matching @p descs,
173 *
174 * @param	bp		Platform state containing a valid EROM parser.
175 * @param	descs		The core match descriptor table.
176 * @param	num_descs	The number of match descriptors in @p descs.
177 * @param[out]	info		If non-NULL, will be populated with the core
178 *				info.
179 * @param[out]	addr		If non-NULL, will be populated with the core's
180 *				physical register address.
181 */
182static int
183bcm_find_core(struct bcm_platform *bp, const struct bhnd_core_match *descs,
184    size_t num_descs, struct bhnd_core_info *info, uintptr_t *addr)
185{
186	bhnd_addr_t		b_addr;
187	bhnd_size_t		b_size;
188	int			error;
189
190	/* Fetch core info */
191	for (size_t i = 0; i < num_descs; i++) {
192		error = bhnd_erom_lookup_core_addr(&bp->erom.obj, &descs[i],
193		    BHND_PORT_DEVICE, 0, 0, info, &b_addr, &b_size);
194
195		/* Terminate search on first match */
196		if (error == 0)
197			break;
198
199		/* Terminate on first error (other than core not found) */
200		if (error != ENOENT)
201			return (error);
202
203		/* Continue search ... */
204	}
205
206	/* Provide the core's base address */
207	if (addr != NULL && b_addr > UINTPTR_MAX) {
208		BCM_ERR("core address %#jx overflows native address width\n",
209		    (uintmax_t)b_addr);
210		return (ERANGE);
211	}
212
213	if (addr != NULL)
214		*addr = b_addr;
215
216	return (0);
217}
218
219/**
220 * Read a variable directly from NVRAM, decoding as @p type.
221 *
222 * @param		bp	Platform state.
223 * @param		name	The raw name of the variable to be fetched,
224 *				including any device path (/pci/1/1/varname) or
225 *				alias prefix (0:varname).
226 * @param[out]		buf	On success, the requested value will be written
227 *				to this buffer. This argment may be NULL if
228 *				the value is not desired.
229 * @param[in,out]	len	The capacity of @p buf. On success, will be set
230 *				to the actual size of the requested value.
231 * @param		type	The data type to be written to @p buf.
232 *
233 * @retval 0		success
234 * @retval ENOMEM	If @p buf is non-NULL and a buffer of @p len is too
235 *			small to hold the requested value.
236 * @retval ENOENT	If @p name is not found.
237 * @retval EFTYPE	If the variable data cannot be coerced to @p type.
238 * @retval ERANGE	If value coercion would overflow @p type.
239 * @retval non-zero	If parsing NVRAM otherwise fails, a regular unix error
240 *			code will be returned.
241 */
242int
243bcm_get_nvram(struct bcm_platform *bp, const char *name, void *buf, size_t *len,
244    bhnd_nvram_type type)
245{
246	if (bp->nvram_io == NULL || bp->nvram_cls == NULL)
247		return (ENOENT);
248
249	return (bhnd_nvram_data_getvar_direct(bp->nvram_cls, bp->nvram_io, name,
250	    buf, len, type));
251}
252
253/**
254 * Probe and attach a bhnd_erom parser instance for the bhnd bus.
255 *
256 * @param[out]	erom_cls	The probed EROM class.
257 * @param[out]	erom_ops	The storage to be used when compiling
258 *				@p erom_cls.
259 * @param[out]	erom		The storage to be used when initializing the
260 *				static instance of @p erom_cls.
261 * @param	esize		The total available number of bytes allocated
262 *				for @p erom. If this is less than is required
263 *				by @p erom_cls ENOMEM will be returned.
264 * @param	eio		EROM I/O callbacks to be used.
265 * @param[out]	cid		On success, the probed chip identification.
266 */
267static int
268bcm_erom_probe_and_attach(bhnd_erom_class_t **erom_cls, kobj_ops_t erom_ops,
269    bhnd_erom_t *erom, size_t esize, struct bhnd_erom_io *eio,
270    struct bhnd_chipid *cid)
271{
272	bhnd_erom_class_t	**clsp;
273	bus_addr_t		  bus_addr;
274	int			  error, prio, result;
275
276	*erom_cls = NULL;
277	prio = 0;
278
279	/* Map our first bus core for the erom probe */
280	bus_addr = bcm_get_bus_addr();
281	if ((error = bhnd_erom_io_map(eio, bus_addr, BHND_DEFAULT_CORE_SIZE))) {
282		BCM_ERR("failed to map first core at %#jx+%#jx: %d\n",
283		    (uintmax_t)bus_addr, (uintmax_t)BHND_DEFAULT_CORE_SIZE,
284		    error);
285
286		return (error);
287	}
288
289	SET_FOREACH(clsp, bhnd_erom_class_set) {
290		struct bhnd_chipid	 pcid;
291		bhnd_erom_class_t	*cls;
292		struct kobj_ops		 kops;
293
294		cls = *clsp;
295
296		/* Compile the class' ops table */
297		kobj_class_compile_static(cls, &kops);
298
299		/* Probe the bus address */
300		result = bhnd_erom_probe(cls, eio, NULL, &pcid);
301
302		/* Drop pointer to stack allocated ops table */
303		cls->ops = NULL;
304
305		/* The parser did not match if an error was returned */
306		if (result > 0)
307			continue;
308
309		/* Check for a new highest priority match */
310		if (*erom_cls == NULL || result > prio) {
311			prio = result;
312
313			*cid = pcid;
314			*erom_cls = cls;
315		}
316
317		/* Terminate immediately on BUS_PROBE_SPECIFIC */
318		if (result == BUS_PROBE_SPECIFIC)
319			break;
320	}
321
322	/* Valid EROM class probed? */
323	if (*erom_cls == NULL) {
324		BCM_ERR("no erom parser found for root bus at %#jx\n",
325		    (uintmax_t)bus_addr);
326
327		return (ENOENT);
328	}
329
330	/* Using the provided storage, recompile the erom class ... */
331	kobj_class_compile_static(*erom_cls, erom_ops);
332
333	/* ... and initialize the erom parser instance */
334	error = bhnd_erom_init_static(*erom_cls, erom, esize, cid, eio);
335
336	return (error);
337}
338
339/**
340 * Populate platform configuration data.
341 */
342static int
343bcm_init_platform_data(struct bcm_platform *bp)
344{
345	bus_addr_t		bus_addr, bus_size;
346	bus_space_tag_t		erom_bst;
347	bus_space_handle_t	erom_bsh;
348	bool			aob, pmu;
349	int			error;
350
351	bus_addr = bcm_get_bus_addr();
352	bus_size = bcm_get_bus_size();
353
354#ifdef CFE
355	/* Fetch CFE console handle (if any). Must be initialized before
356	 * any calls to printf/early_putc. */
357	if ((bp->cfe_console = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE)) < 0)
358		bp->cfe_console = -1;
359
360	/* Probe CFE NVRAM sources */
361	bp->nvram_io = &bcm_cfe_nvram.io;
362	error = bcm_nvram_find_cfedev(&bcm_cfe_nvram, &bp->nvram_cls);
363	if (error) {
364		bp->nvram_io = NULL;
365		bp->nvram_cls = NULL;
366	}
367#endif /* CFE */
368
369	/* Probe and attach device table provider, populating our
370	 * chip identification */
371	erom_bst = mips_bus_space_generic;
372	erom_bsh = BCM_SOC_BSH(bus_addr, 0);
373
374	error = bhnd_erom_iobus_init(&bp->erom_io, bus_addr, bus_size, erom_bst,
375	    erom_bsh);
376	if (error) {
377		BCM_ERR("failed to initialize erom I/O callbacks: %d\n", error);
378		return (error);
379	}
380
381	error = bcm_erom_probe_and_attach(&bp->erom_impl, &bp->erom_ops,
382	    &bp->erom.obj, sizeof(bp->erom), &bp->erom_io.eio, &bp->cid);
383	if (error) {
384		BCM_ERR("error attaching erom parser: %d\n", error);
385		bhnd_erom_io_fini(&bp->erom_io.eio);
386		return (error);
387	}
388
389	if (bootverbose)
390		bhnd_erom_dump(&bp->erom.obj);
391
392	/* Fetch chipcommon core info */
393	error = bcm_find_core(bp, bcm_chipc_cores, nitems(bcm_chipc_cores),
394	    &bp->cc_id, &bp->cc_addr);
395	if (error) {
396		BCM_ERR("error locating chipc core: %d\n", error);
397		return (error);
398	}
399
400	/* Fetch chipc capability flags */
401	bp->cc_caps = BCM_SOC_READ_4(bp->cc_addr, CHIPC_CAPABILITIES);
402	bp->cc_caps_ext = 0x0;
403
404	if (CHIPC_HWREV_HAS_CAP_EXT(bp->cc_id.hwrev))
405		bp->cc_caps_ext = BCM_CHIPC_READ_4(bp, CHIPC_CAPABILITIES_EXT);
406
407	/* Fetch PMU info */
408	pmu = CHIPC_GET_FLAG(bp->cc_caps, CHIPC_CAP_PMU);
409	aob = CHIPC_GET_FLAG(bp->cc_caps_ext, CHIPC_CAP2_AOB);
410
411	if (pmu && aob) {
412		/* PMU block mapped to a PMU core on the Always-on-Bus (aob) */
413		error = bcm_find_core(bp, bcm_pmu_cores, nitems(bcm_pmu_cores),
414		    &bp->pmu_id,  &bp->pmu_addr);
415		if (error) {
416			BCM_ERR("error locating pmu core: %d\n", error);
417			return (error);
418		}
419	} else if (pmu) {
420		/* PMU block mapped to chipc */
421		bp->pmu_addr = bp->cc_addr;
422		bp->pmu_id = bp->cc_id;
423	} else {
424		/* No PMU */
425		bp->pmu_addr = 0x0;
426		memset(&bp->pmu_id, 0, sizeof(bp->pmu_id));
427	}
428
429	/* Initialize PMU query state */
430	if (pmu) {
431		error = bhnd_pmu_query_init(&bp->pmu, NULL, bp->cid,
432		    &bcm_pmu_soc_io, bp);
433		if (error) {
434			BCM_ERR("bhnd_pmu_query_init() failed: %d\n", error);
435			return (error);
436		}
437	}
438
439	/* Find CPU core info */
440	error = bcm_find_core(bp, bcm_cpu0_cores, nitems(bcm_cpu0_cores),
441	    &bp->cpu_id,  &bp->cpu_addr);
442	if (error) {
443		BCM_ERR("error locating CPU core: %d\n", error);
444		return (error);
445	}
446
447	/* Initialize our platform service registry */
448	if ((error = bhnd_service_registry_init(&bp->services))) {
449		BCM_ERR("error initializing service registry: %d\n", error);
450		return (error);
451	}
452
453	bcm_platform_data_avail = true;
454	return (0);
455}
456
457void
458platform_cpu_init()
459{
460	/* Nothing special */
461}
462
463static void
464mips_init(void)
465{
466	int i, j;
467
468	printf("entry: mips_init()\n");
469
470#ifdef CFE
471	/*
472	 * Query DRAM memory map from CFE.
473	 */
474	physmem = 0;
475	for (i = 0; i < 10; i += 2) {
476		int result;
477		uint64_t addr, len, type;
478
479		result = cfe_enummem(i / 2, 0, &addr, &len, &type);
480		if (result < 0) {
481			BCM_TRACE("There is no phys memory for: %d\n", i);
482			phys_avail[i] = phys_avail[i + 1] = 0;
483			break;
484		}
485		if (type != CFE_MI_AVAILABLE) {
486			BCM_TRACE("phys memory is not available: %d\n", i);
487			continue;
488		}
489
490		phys_avail[i] = addr;
491		if (i == 0 && addr == 0) {
492			/*
493			 * If this is the first physical memory segment probed
494			 * from CFE, omit the region at the start of physical
495			 * memory where the kernel has been loaded.
496			 */
497			phys_avail[i] += MIPS_KSEG0_TO_PHYS(kernel_kseg0_end);
498		}
499
500		BCM_TRACE("phys memory is available for: %d\n", i);
501		BCM_TRACE(" => addr =  %jx\n", addr);
502		BCM_TRACE(" => len =  %jd\n", len);
503
504		phys_avail[i + 1] = addr + len;
505		physmem += len;
506	}
507
508	BCM_TRACE("Total phys memory is : %ld\n", physmem);
509	realmem = btoc(physmem);
510#endif
511
512	for (j = 0; j < i; j++)
513		dump_avail[j] = phys_avail[j];
514
515	physmem = realmem;
516
517	init_param1();
518	init_param2(physmem);
519	mips_cpu_init();
520	pmap_bootstrap();
521	mips_proc0_init();
522	mutex_init();
523	kdb_init();
524#ifdef KDB
525	if (boothowto & RB_KDB)
526		kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger");
527#endif
528}
529
530void
531platform_reset(void)
532{
533	struct bcm_platform	*bp;
534	bool			 bcm4785war;
535
536	printf("bcm::platform_reset()\n");
537	intr_disable();
538
539#ifdef CFE
540	/* Fall back on CFE if reset requested during platform
541	 * data initialization */
542	if (!bcm_platform_data_avail) {
543		cfe_exit(0, 0);
544		while (1);
545	}
546#endif
547
548	bp = bcm_get_platform();
549	bcm4785war = false;
550
551	/* Handle BCM4785-specific behavior */
552	if (bp->cid.chip_id == BHND_CHIPID_BCM4785) {
553		bcm4785war = true;
554
555		/* Switch to async mode */
556		bcm_bmips_wr_pllcfg3(BMIPS_BCMCFG_PLLCFG3_SM);
557	}
558
559	/* Set watchdog (PMU or ChipCommon) */
560	if (bp->pmu_addr != 0x0) {
561		BCM_PMU_WRITE_4(bp, BHND_PMU_WATCHDOG, 1);
562	} else
563		BCM_CHIPC_WRITE_4(bp, CHIPC_WATCHDOG, 1);
564
565	/* BCM4785 */
566	if (bcm4785war) {
567		mips_sync();
568		__asm __volatile("wait");
569	}
570
571	while (1);
572}
573
574void
575platform_start(__register_t a0, __register_t a1, __register_t a2,
576	       __register_t a3)
577{
578	vm_offset_t 		 kernend;
579	uint64_t		 platform_counter_freq;
580	int			 error;
581
582	/* clear the BSS and SBSS segments */
583	kernend = (vm_offset_t)&end;
584	memset(&edata, 0, kernend - (vm_offset_t)(&edata));
585
586	mips_postboot_fixup();
587
588	/* Initialize pcpu stuff */
589	mips_pcpu0_init();
590
591#ifdef CFE
592	/*
593	 * Initialize CFE firmware trampolines. This must be done
594	 * before any CFE APIs are called, including writing
595	 * to the CFE console.
596	 *
597	 * CFE passes the following values in registers:
598	 * a0: firmware handle
599	 * a2: firmware entry point
600	 * a3: entry point seal
601	 */
602	if (a3 == CFE_EPTSEAL)
603		cfe_init(a0, a2);
604#endif
605
606	/* Init BCM platform data */
607	if ((error = bcm_init_platform_data(&bcm_platform_data)))
608		panic("bcm_init_platform_data() failed: %d", error);
609
610	platform_counter_freq = bcm_get_cpufreq(bcm_get_platform());
611
612	/* CP0 ticks every two cycles */
613	mips_timer_early_init(platform_counter_freq / 2);
614
615	cninit();
616
617	mips_init();
618
619	mips_timer_init_params(platform_counter_freq, 1);
620}
621
622/*
623 * CFE-based EARLY_PRINTF support. To use, add the following to the kernel
624 * config:
625 *	option EARLY_PRINTF
626 *	option CFE
627 *	device cfe
628 */
629#if defined(EARLY_PRINTF) && defined(CFE)
630static void
631bcm_cfe_eputc(int c)
632{
633	unsigned char	ch;
634	int		handle;
635
636	ch = (unsigned char) c;
637
638	/* bcm_get_platform() cannot be used here, as we may be called
639	 * from bcm_init_platform_data(). */
640	if ((handle = bcm_platform_data.cfe_console) < 0)
641		return;
642
643	if (ch == '\n')
644		early_putc('\r');
645
646	while ((cfe_write(handle, &ch, 1)) == 0)
647		continue;
648}
649
650early_putc_t *early_putc = bcm_cfe_eputc;
651#endif /* EARLY_PRINTF */
652