]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/broadcom/bcm_machdep.c
Merge ACPICA 20170531.
[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  *
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
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.
16  *
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
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include "opt_ddb.h"
34
35 #include <sys/param.h>
36 #include <sys/conf.h>
37 #include <sys/kernel.h>
38 #include <sys/systm.h>
39 #include <sys/imgact.h>
40 #include <sys/bio.h>
41 #include <sys/buf.h>
42 #include <sys/bus.h>
43 #include <sys/cpu.h>
44 #include <sys/cons.h>
45 #include <sys/exec.h>
46 #include <sys/ucontext.h>
47 #include <sys/proc.h>
48 #include <sys/kdb.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>
54 #include <sys/user.h>
55
56 #include <vm/vm.h>
57 #include <vm/vm_object.h>
58 #include <vm/vm_page.h>
59
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>
74
75 #include <dev/bhnd/bhnd.h>
76 #include <dev/bhnd/bhndreg.h>
77
78 #include <dev/bhnd/bcma/bcma_eromvar.h>
79
80 #include <dev/bhnd/siba/sibareg.h>
81 #include <dev/bhnd/siba/sibavar.h>
82
83 #include <dev/bhnd/cores/chipc/chipcreg.h>
84 #include <dev/bhnd/cores/pmu/bhnd_pmureg.h>
85
86 #include "bcm_machdep.h"
87 #include "bcm_bmips_exts.h"
88
89 #ifdef CFE
90 #include <dev/cfe/cfe_api.h>
91 #include <dev/cfe/cfe_error.h>
92 #endif
93
94 #if 0
95 #define BCM_TRACE(_fmt, ...)    printf(_fmt, ##__VA_ARGS__)
96 #else
97 #define BCM_TRACE(_fmt, ...)
98 #endif
99
100 static int      bcm_init_platform_data(struct bcm_platform *bp);
101
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);
105
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);
109
110 extern int      *edata;
111 extern int      *end;
112
113 static struct bcm_platform       bcm_platform_data;
114 static bool                      bcm_platform_data_avail = false;
115
116 #ifdef CFE
117 static struct bcm_nvram_iocfe    bcm_cfe_nvram;
118 #endif
119
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)    },
123 };
124
125 static const struct bhnd_core_match bcm_pmu_cores[] = {
126         { BHND_MATCH_CORE(BHND_MFGID_BCM,       BHND_COREID_PMU)        },
127 };
128
129 struct bcm_platform *
130 bcm_get_platform(void)
131 {
132         if (!bcm_platform_data_avail)
133                 panic("platform data not available");
134
135         return (&bcm_platform_data);
136 }
137
138 static bus_addr_t
139 bcm_get_bus_addr(void)
140 {
141         long maddr;
142
143         if (resource_long_value("bhnd", 0, "maddr", &maddr) == 0)
144                 return ((u_long)maddr);
145
146         return (BHND_DEFAULT_CHIPC_ADDR);
147 }
148
149 /**
150  * Search the device enumeration table for a core matching @p descs,
151  * 
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
156  *                              info.
157  * @param[out]  addr            If non-NULL, will be populated with the core's
158  *                              physical register address.
159  */
160 static int
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)
163 {
164         bhnd_addr_t             b_addr;
165         bhnd_size_t             b_size;
166         int                     error;
167
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);
172
173                 /* Terminate search on first match */
174                 if (error == 0)
175                         break;
176
177                 /* Terminate on first error (other than core not found) */
178                 if (error != ENOENT)
179                         return (error);
180
181                 /* Continue search ... */
182         }
183
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",
187                     (uintmax_t)b_addr);
188                 return (ERANGE);
189         }
190
191         if (addr != NULL)
192                 *addr = b_addr;
193
194         return (0);
195 }
196
197 /**
198  * Read a variable directly from NVRAM, decoding as @p type.
199  *
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.
210  *
211  * @retval 0            success
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.
219  */
220 int
221 bcm_get_nvram(struct bcm_platform *bp, const char *name, void *buf, size_t *len,
222     bhnd_nvram_type type)
223 {
224         if (bp->nvram_io == NULL || bp->nvram_cls == NULL)
225                 return (ENOENT);
226
227         return (bhnd_nvram_data_getvar_direct(bp->nvram_cls, bp->nvram_io, name,
228             buf, len, type));
229 }
230
231 /**
232  * Probe and attach a bhnd_erom parser instance for the bhnd bus.
233  * 
234  * @param[out]  erom_cls        The probed EROM class.
235  * @param[out]  erom_ops        The storage to be used when compiling
236  *                              @p erom_cls.
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.
243  */
244 static int
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)
247 {
248         bhnd_erom_class_t       **clsp;
249         bus_space_tag_t           bst;
250         bus_space_handle_t        bsh;
251         bus_addr_t                bus_addr;
252         int                       error, prio, result;
253
254         bus_addr = bcm_get_bus_addr();
255         *erom_cls = NULL;
256         prio = 0;
257
258         bst = mips_bus_space_generic;
259         bsh = BCM_SOC_BSH(bus_addr, 0);
260
261         SET_FOREACH(clsp, bhnd_erom_class_set) {
262                 struct bhnd_chipid       pcid;
263                 bhnd_erom_class_t       *cls;
264                 struct kobj_ops          kops;
265
266                 cls = *clsp;
267
268                 /* Compile the class' ops table */
269                 kobj_class_compile_static(cls, &kops);
270
271                 /* Probe the bus address */
272                 result = bhnd_erom_probe_static(cls, bst, bsh, bus_addr, NULL,
273                     &pcid);
274
275                 /* Drop pointer to stack allocated ops table */
276                 cls->ops = NULL;
277
278                 /* The parser did not match if an error was returned */
279                 if (result > 0)
280                         continue;
281
282                 /* Check for a new highest priority match */
283                 if (*erom_cls == NULL || result > prio) {
284                         prio = result;
285
286                         *cid = pcid;
287                         *erom_cls = cls;
288                 }
289
290                 /* Terminate immediately on BUS_PROBE_SPECIFIC */
291                 if (result == BUS_PROBE_SPECIFIC)
292                         break;
293         }
294
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);
299                 return (ENOENT);
300         }
301
302         /* Using the provided storage, recompile the erom class ... */
303         kobj_class_compile_static(*erom_cls, erom_ops);
304
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);
309
310         return (error);
311 }
312
313 /**
314  * Populate platform configuration data.
315  */
316 static int
317 bcm_init_platform_data(struct bcm_platform *bp)
318 {
319         bool    aob, pmu;
320         int     error;
321
322 #ifdef CFE
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;
327
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);
331         if (error) {
332                 bp->nvram_io = NULL;
333                 bp->nvram_cls = NULL;
334         }
335 #endif /* CFE */
336
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);
341         if (error) {
342                 BCM_ERR("error attaching erom parser: %d\n", error);
343                 return (error);
344         }
345
346         if (bootverbose)
347                 bhnd_erom_dump(&bp->erom.obj);
348
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);
352         if (error) {
353                 BCM_ERR("error locating chipc core: %d\n", error);
354                 return (error);
355         }
356
357         /* Fetch chipc capability flags */
358         bp->cc_caps = BCM_SOC_READ_4(bp->cc_addr, CHIPC_CAPABILITIES);
359         bp->cc_caps_ext = 0x0;  
360
361         if (CHIPC_HWREV_HAS_CAP_EXT(bp->cc_id.hwrev))
362                 bp->cc_caps_ext = BCM_CHIPC_READ_4(bp, CHIPC_CAPABILITIES_EXT);
363
364         /* Fetch PMU info */
365         pmu = CHIPC_GET_FLAG(bp->cc_caps, CHIPC_CAP_PMU);
366         aob = CHIPC_GET_FLAG(bp->cc_caps_ext, CHIPC_CAP2_AOB);
367
368         if (pmu && 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);
372                 if (error) {
373                         BCM_ERR("error locating pmu core: %d\n", error);
374                         return (error);
375                 }
376         } else if (pmu) {
377                 /* PMU block mapped to chipc */
378                 bp->pmu_addr = bp->cc_addr;
379                 bp->pmu_id = bp->cc_id;
380         } else {
381                 /* No PMU */
382                 bp->pmu_addr = 0x0;
383                 memset(&bp->pmu_id, 0, sizeof(bp->pmu_id));
384         }
385
386         /* Initialize PMU query state */
387         if (pmu) {
388                 error = bhnd_pmu_query_init(&bp->pmu, NULL, bp->cid,
389                     &bcm_pmu_soc_io, bp);
390                 if (error) {
391                         BCM_ERR("bhnd_pmu_query_init() failed: %d\n", error);
392                         return (error);
393                 }
394         }
395
396         bcm_platform_data_avail = true;
397         return (0);
398 }
399
400 void
401 platform_cpu_init()
402 {
403         /* Nothing special */
404 }
405
406 static void
407 mips_init(void)
408 {
409         int i, j;
410
411         printf("entry: mips_init()\n");
412
413 #ifdef CFE
414         /*
415          * Query DRAM memory map from CFE.
416          */
417         physmem = 0;
418         for (i = 0; i < 10; i += 2) {
419                 int result;
420                 uint64_t addr, len, type;
421
422                 result = cfe_enummem(i / 2, 0, &addr, &len, &type);
423                 if (result < 0) {
424                         BCM_TRACE("There is no phys memory for: %d\n", i);
425                         phys_avail[i] = phys_avail[i + 1] = 0;
426                         break;
427                 }
428                 if (type != CFE_MI_AVAILABLE) {
429                         BCM_TRACE("phys memory is not available: %d\n", i);
430                         continue;
431                 }
432
433                 phys_avail[i] = addr;
434                 if (i == 0 && addr == 0) {
435                         /*
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.
439                          */
440                         phys_avail[i] += MIPS_KSEG0_TO_PHYS(kernel_kseg0_end);
441                 }
442                 
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);
446
447                 phys_avail[i + 1] = addr + len;
448                 physmem += len;
449         }
450
451         BCM_TRACE("Total phys memory is : %ld\n", physmem);
452         realmem = btoc(physmem);
453 #endif
454
455         for (j = 0; j < i; j++)
456                 dump_avail[j] = phys_avail[j];
457
458         physmem = realmem;
459
460         init_param1();
461         init_param2(physmem);
462         mips_cpu_init();
463         pmap_bootstrap();
464         mips_proc0_init();
465         mutex_init();
466         kdb_init();
467 #ifdef KDB
468         if (boothowto & RB_KDB)
469                 kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger");
470 #endif
471 }
472
473 void
474 platform_reset(void)
475 {
476         struct bcm_platform     *bp;
477         bool                     bcm4785war;
478
479         printf("bcm::platform_reset()\n");
480         intr_disable();
481
482 #ifdef CFE
483         /* Fall back on CFE if reset requested during platform
484          * data initialization */
485         if (!bcm_platform_data_avail) {
486                 cfe_exit(0, 0);
487                 while (1);
488         }
489 #endif
490
491         bp = bcm_get_platform();
492         bcm4785war = false;
493
494         /* Handle BCM4785-specific behavior */
495         if (bp->cid.chip_id == BHND_CHIPID_BCM4785) {
496                 bcm4785war = true;
497
498                 /* Switch to async mode */
499                 bcm_bmips_wr_pllcfg3(BMIPS_BCMCFG_PLLCFG3_SM);
500         }
501
502         /* Set watchdog (PMU or ChipCommon) */
503         if (bp->pmu_addr != 0x0) {
504                 BCM_PMU_WRITE_4(bp, BHND_PMU_WATCHDOG, 1);
505         } else
506                 BCM_CHIPC_WRITE_4(bp, CHIPC_WATCHDOG, 1);
507
508         /* BCM4785 */
509         if (bcm4785war) {
510                 mips_sync();
511                 __asm __volatile("wait");
512         }
513
514         while (1);
515 }
516
517 void
518 platform_start(__register_t a0, __register_t a1, __register_t a2,
519                __register_t a3)
520 {
521         vm_offset_t              kernend;
522         uint64_t                 platform_counter_freq;
523         int                      error;
524
525         /* clear the BSS and SBSS segments */
526         kernend = (vm_offset_t)&end;
527         memset(&edata, 0, kernend - (vm_offset_t)(&edata));
528
529         mips_postboot_fixup();
530
531         /* Initialize pcpu stuff */
532         mips_pcpu0_init();
533
534 #ifdef CFE
535         /*
536          * Initialize CFE firmware trampolines. This must be done
537          * before any CFE APIs are called, including writing
538          * to the CFE console.
539          *
540          * CFE passes the following values in registers:
541          * a0: firmware handle
542          * a2: firmware entry point
543          * a3: entry point seal
544          */
545         if (a3 == CFE_EPTSEAL)
546                 cfe_init(a0, a2);
547 #endif
548
549         /* Init BCM platform data */
550         if ((error = bcm_init_platform_data(&bcm_platform_data)))
551                 panic("bcm_init_platform_data() failed: %d", error);
552
553         platform_counter_freq = bcm_get_cpufreq(bcm_get_platform());
554
555         /* CP0 ticks every two cycles */
556         mips_timer_early_init(platform_counter_freq / 2);
557
558         cninit();
559
560         mips_init();
561
562         mips_timer_init_params(platform_counter_freq, 1);
563 }
564
565 /*
566  * CFE-based EARLY_PRINTF support. To use, add the following to the kernel
567  * config:
568  *      option EARLY_PRINTF
569  *      option CFE
570  *      device cfe
571  */
572 #if defined(EARLY_PRINTF) && defined(CFE)
573 static void
574 bcm_cfe_eputc(int c)
575 {
576         unsigned char   ch;
577         int             handle;
578
579         ch = (unsigned char) c;
580
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)
584                 return;
585
586         if (ch == '\n')
587                 early_putc('\r');
588
589         while ((cfe_write(handle, &ch, 1)) == 0)
590                 continue;
591 }
592
593 early_putc_t *early_putc = bcm_cfe_eputc;
594 #endif /* EARLY_PRINTF */