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