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