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>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
35 #include <sys/param.h>
37 #include <sys/kernel.h>
38 #include <sys/systm.h>
39 #include <sys/imgact.h>
46 #include <sys/ucontext.h>
49 #include <sys/ptrace.h>
50 #include <sys/reboot.h>
51 #include <sys/signalvar.h>
52 #include <sys/sysent.h>
53 #include <sys/sysproto.h>
57 #include <vm/vm_object.h>
58 #include <vm/vm_page.h>
60 #include <machine/cache.h>
61 #include <machine/clock.h>
62 #include <machine/cpu.h>
63 #include <machine/cpuinfo.h>
64 #include <machine/cpufunc.h>
65 #include <machine/cpuregs.h>
66 #include <machine/hwfunc.h>
67 #include <machine/intr_machdep.h>
68 #include <machine/locore.h>
69 #include <machine/md_var.h>
70 #include <machine/pte.h>
71 #include <machine/sigframe.h>
72 #include <machine/trap.h>
73 #include <machine/vmparam.h>
75 #include <dev/bhnd/bhnd.h>
76 #include <dev/bhnd/bhndreg.h>
78 #include <dev/bhnd/bcma/bcma_eromvar.h>
80 #include <dev/bhnd/siba/sibareg.h>
81 #include <dev/bhnd/siba/sibavar.h>
83 #include <dev/bhnd/cores/chipc/chipcreg.h>
84 #include <dev/bhnd/cores/pmu/bhnd_pmureg.h>
86 #include "bcm_machdep.h"
87 #include "bcm_bmips_exts.h"
90 #include <dev/cfe/cfe_api.h>
91 #include <dev/cfe/cfe_error.h>
95 #define BCM_TRACE(_fmt, ...) printf(_fmt, ##__VA_ARGS__)
97 #define BCM_TRACE(_fmt, ...)
100 static int bcm_init_platform_data(struct bcm_platform *bp);
102 static int bcm_find_core(struct bcm_platform *bp,
103 const struct bhnd_core_match *descs, size_t num_descs,
104 struct bhnd_core_info *info, uintptr_t *addr);
106 static int bcm_erom_probe_and_attach(bhnd_erom_class_t **erom_cls,
107 kobj_ops_t erom_ops, bhnd_erom_t *erom, size_t esize,
108 struct bhnd_chipid *cid);
113 static struct bcm_platform bcm_platform_data;
114 static bool bcm_platform_data_avail = false;
117 static struct bcm_nvram_iocfe bcm_cfe_nvram;
120 static const struct bhnd_core_match bcm_chipc_cores[] = {
121 { BHND_MATCH_CORE(BHND_MFGID_BCM, BHND_COREID_CC) },
122 { BHND_MATCH_CORE(BHND_MFGID_BCM, BHND_COREID_4706_CC) },
125 static const struct bhnd_core_match bcm_pmu_cores[] = {
126 { BHND_MATCH_CORE(BHND_MFGID_BCM, BHND_COREID_PMU) },
129 struct bcm_platform *
130 bcm_get_platform(void)
132 if (!bcm_platform_data_avail)
133 panic("platform data not available");
135 return (&bcm_platform_data);
139 bcm_get_bus_addr(void)
143 if (resource_long_value("bhnd", 0, "maddr", &maddr) == 0)
144 return ((u_long)maddr);
146 return (BHND_DEFAULT_CHIPC_ADDR);
150 * Search the device enumeration table for a core matching @p descs,
152 * @param bp Platform state containing a valid EROM parser.
153 * @param descs The core match descriptor table.
154 * @param num_descs The number of match descriptors in @p descs.
155 * @param[out] info If non-NULL, will be populated with the core
157 * @param[out] addr If non-NULL, will be populated with the core's
158 * physical register address.
161 bcm_find_core(struct bcm_platform *bp, const struct bhnd_core_match *descs,
162 size_t num_descs, struct bhnd_core_info *info, uintptr_t *addr)
168 /* Fetch core info */
169 for (size_t i = 0; i < num_descs; i++) {
170 error = bhnd_erom_lookup_core_addr(&bp->erom.obj, &descs[i],
171 BHND_PORT_DEVICE, 0, 0, info, &b_addr, &b_size);
173 /* Terminate search on first match */
177 /* Terminate on first error (other than core not found) */
181 /* Continue search ... */
184 /* Provide the core's base address */
185 if (addr != NULL && b_addr > UINTPTR_MAX) {
186 BCM_ERR("core address %#jx overflows native address width\n",
198 * Read a variable directly from NVRAM, decoding as @p type.
200 * @param bp Platform state.
201 * @param name The raw name of the variable to be fetched,
202 * including any device path (/pci/1/1/varname) or
203 * alias prefix (0:varname).
204 * @param[out] buf On success, the requested value will be written
205 * to this buffer. This argment may be NULL if
206 * the value is not desired.
207 * @param[in,out] len The capacity of @p buf. On success, will be set
208 * to the actual size of the requested value.
209 * @param type The data type to be written to @p buf.
212 * @retval ENOMEM If @p buf is non-NULL and a buffer of @p len is too
213 * small to hold the requested value.
214 * @retval ENOENT If @p name is not found.
215 * @retval EFTYPE If the variable data cannot be coerced to @p type.
216 * @retval ERANGE If value coercion would overflow @p type.
217 * @retval non-zero If parsing NVRAM otherwise fails, a regular unix error
218 * code will be returned.
221 bcm_get_nvram(struct bcm_platform *bp, const char *name, void *buf, size_t *len,
222 bhnd_nvram_type type)
224 if (bp->nvram_io == NULL || bp->nvram_cls == NULL)
227 return (bhnd_nvram_data_getvar_direct(bp->nvram_cls, bp->nvram_io, name,
232 * Probe and attach a bhnd_erom parser instance for the bhnd bus.
234 * @param[out] erom_cls The probed EROM class.
235 * @param[out] erom_ops The storage to be used when compiling
237 * @param[out] erom The storage to be used when initializing the
238 * static instance of @p erom_cls.
239 * @param esize The total available number of bytes allocated
240 * for @p erom. If this is less than is required
241 * by @p erom_cls ENOMEM will be returned.
242 * @param[out] cid On success, the probed chip identification.
245 bcm_erom_probe_and_attach(bhnd_erom_class_t **erom_cls, kobj_ops_t erom_ops,
246 bhnd_erom_t *erom, size_t esize, struct bhnd_chipid *cid)
248 bhnd_erom_class_t **clsp;
250 bus_space_handle_t bsh;
252 int error, prio, result;
254 bus_addr = bcm_get_bus_addr();
258 bst = mips_bus_space_generic;
259 bsh = BCM_SOC_BSH(bus_addr, 0);
261 SET_FOREACH(clsp, bhnd_erom_class_set) {
262 struct bhnd_chipid pcid;
263 bhnd_erom_class_t *cls;
264 struct kobj_ops kops;
268 /* Compile the class' ops table */
269 kobj_class_compile_static(cls, &kops);
271 /* Probe the bus address */
272 result = bhnd_erom_probe_static(cls, bst, bsh, bus_addr, NULL,
275 /* Drop pointer to stack allocated ops table */
278 /* The parser did not match if an error was returned */
282 /* Check for a new highest priority match */
283 if (*erom_cls == NULL || result > prio) {
290 /* Terminate immediately on BUS_PROBE_SPECIFIC */
291 if (result == BUS_PROBE_SPECIFIC)
295 /* Valid EROM class probed? */
296 if (*erom_cls == NULL) {
297 BCM_ERR("no erom parser found for root bus at %#jx\n",
298 (uintmax_t)bus_addr);
302 /* Using the provided storage, recompile the erom class ... */
303 kobj_class_compile_static(*erom_cls, erom_ops);
305 /* ... and initialize the erom parser instance */
306 bsh = BCM_SOC_BSH(cid->enum_addr, 0);
307 error = bhnd_erom_init_static(*erom_cls, erom, esize, cid,
308 mips_bus_space_generic, bsh);
314 * Populate platform configuration data.
317 bcm_init_platform_data(struct bcm_platform *bp)
323 /* Fetch CFE console handle (if any). Must be initialized before
324 * any calls to printf/early_putc. */
325 if ((bp->cfe_console = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE)) < 0)
326 bp->cfe_console = -1;
328 /* Probe CFE NVRAM sources */
329 bp->nvram_io = &bcm_cfe_nvram.io;
330 error = bcm_nvram_find_cfedev(&bcm_cfe_nvram, &bp->nvram_cls);
333 bp->nvram_cls = NULL;
337 /* Probe and attach device table provider, populating our
338 * chip identification */
339 error = bcm_erom_probe_and_attach(&bp->erom_impl, &bp->erom_ops,
340 &bp->erom.obj, sizeof(bp->erom), &bp->cid);
342 BCM_ERR("error attaching erom parser: %d\n", error);
347 bhnd_erom_dump(&bp->erom.obj);
349 /* Fetch chipcommon core info */
350 error = bcm_find_core(bp, bcm_chipc_cores, nitems(bcm_chipc_cores),
351 &bp->cc_id, &bp->cc_addr);
353 BCM_ERR("error locating chipc core: %d\n", error);
357 /* Fetch chipc capability flags */
358 bp->cc_caps = BCM_SOC_READ_4(bp->cc_addr, CHIPC_CAPABILITIES);
359 bp->cc_caps_ext = 0x0;
361 if (CHIPC_HWREV_HAS_CAP_EXT(bp->cc_id.hwrev))
362 bp->cc_caps_ext = BCM_CHIPC_READ_4(bp, CHIPC_CAPABILITIES_EXT);
365 pmu = CHIPC_GET_FLAG(bp->cc_caps, CHIPC_CAP_PMU);
366 aob = CHIPC_GET_FLAG(bp->cc_caps_ext, CHIPC_CAP2_AOB);
369 /* PMU block mapped to a PMU core on the Always-on-Bus (aob) */
370 error = bcm_find_core(bp, bcm_pmu_cores, nitems(bcm_pmu_cores),
371 &bp->pmu_id, &bp->pmu_addr);
373 BCM_ERR("error locating pmu core: %d\n", error);
377 /* PMU block mapped to chipc */
378 bp->pmu_addr = bp->cc_addr;
379 bp->pmu_id = bp->cc_id;
383 memset(&bp->pmu_id, 0, sizeof(bp->pmu_id));
386 /* Initialize PMU query state */
388 error = bhnd_pmu_query_init(&bp->pmu, NULL, bp->cid,
389 &bcm_pmu_soc_io, bp);
391 BCM_ERR("bhnd_pmu_query_init() failed: %d\n", error);
396 bcm_platform_data_avail = true;
403 /* Nothing special */
411 printf("entry: mips_init()\n");
415 * Query DRAM memory map from CFE.
418 for (i = 0; i < 10; i += 2) {
420 uint64_t addr, len, type;
422 result = cfe_enummem(i / 2, 0, &addr, &len, &type);
424 BCM_TRACE("There is no phys memory for: %d\n", i);
425 phys_avail[i] = phys_avail[i + 1] = 0;
428 if (type != CFE_MI_AVAILABLE) {
429 BCM_TRACE("phys memory is not available: %d\n", i);
433 phys_avail[i] = addr;
434 if (i == 0 && addr == 0) {
436 * If this is the first physical memory segment probed
437 * from CFE, omit the region at the start of physical
438 * memory where the kernel has been loaded.
440 phys_avail[i] += MIPS_KSEG0_TO_PHYS(kernel_kseg0_end);
443 BCM_TRACE("phys memory is available for: %d\n", i);
444 BCM_TRACE(" => addr = %jx\n", addr);
445 BCM_TRACE(" => len = %jd\n", len);
447 phys_avail[i + 1] = addr + len;
451 BCM_TRACE("Total phys memory is : %ld\n", physmem);
452 realmem = btoc(physmem);
455 for (j = 0; j < i; j++)
456 dump_avail[j] = phys_avail[j];
461 init_param2(physmem);
468 if (boothowto & RB_KDB)
469 kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger");
476 struct bcm_platform *bp;
479 printf("bcm::platform_reset()\n");
483 /* Fall back on CFE if reset requested during platform
484 * data initialization */
485 if (!bcm_platform_data_avail) {
491 bp = bcm_get_platform();
494 /* Handle BCM4785-specific behavior */
495 if (bp->cid.chip_id == BHND_CHIPID_BCM4785) {
498 /* Switch to async mode */
499 bcm_bmips_wr_pllcfg3(BMIPS_BCMCFG_PLLCFG3_SM);
502 /* Set watchdog (PMU or ChipCommon) */
503 if (bp->pmu_addr != 0x0) {
504 BCM_PMU_WRITE_4(bp, BHND_PMU_WATCHDOG, 1);
506 BCM_CHIPC_WRITE_4(bp, CHIPC_WATCHDOG, 1);
511 __asm __volatile("wait");
518 platform_start(__register_t a0, __register_t a1, __register_t a2,
522 uint64_t platform_counter_freq;
525 /* clear the BSS and SBSS segments */
526 kernend = (vm_offset_t)&end;
527 memset(&edata, 0, kernend - (vm_offset_t)(&edata));
529 mips_postboot_fixup();
531 /* Initialize pcpu stuff */
536 * Initialize CFE firmware trampolines. This must be done
537 * before any CFE APIs are called, including writing
538 * to the CFE console.
540 * CFE passes the following values in registers:
541 * a0: firmware handle
542 * a2: firmware entry point
543 * a3: entry point seal
545 if (a3 == CFE_EPTSEAL)
549 /* Init BCM platform data */
550 if ((error = bcm_init_platform_data(&bcm_platform_data)))
551 panic("bcm_init_platform_data() failed: %d", error);
553 platform_counter_freq = bcm_get_cpufreq(bcm_get_platform());
555 /* CP0 ticks every two cycles */
556 mips_timer_early_init(platform_counter_freq / 2);
562 mips_timer_init_params(platform_counter_freq, 1);
566 * CFE-based EARLY_PRINTF support. To use, add the following to the kernel
568 * option EARLY_PRINTF
572 #if defined(EARLY_PRINTF) && defined(CFE)
579 ch = (unsigned char) c;
581 /* bcm_get_platform() cannot be used here, as we may be called
582 * from bcm_init_platform_data(). */
583 if ((handle = bcm_platform_data.cfe_console) < 0)
589 while ((cfe_write(handle, &ch, 1)) == 0)
593 early_putc_t *early_putc = bcm_cfe_eputc;
594 #endif /* EARLY_PRINTF */