]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/bhnd/siba/siba_erom.c
Merge lldb trunk r321017 to contrib/llvm/tools/lldb.
[FreeBSD/FreeBSD.git] / sys / dev / bhnd / siba / siba_erom.c
1 /*-
2  * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
3  * Copyright (c) 2017 The FreeBSD Foundation
4  * All rights reserved.
5  *
6  * Portions of this software were developed by Landon Fuller
7  * under sponsorship from the FreeBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer,
14  *    without modification.
15  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
16  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
17  *    redistribution must be conditioned upon including a substantially
18  *    similar Disclaimer requirement for further binary redistribution.
19  *
20  * NO WARRANTY
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
24  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
25  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
26  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
29  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31  * THE POSSIBILITY OF SUCH DAMAGES.
32  */
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 #include <sys/param.h>
38 #include <sys/bus.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/module.h>
42
43 #include <machine/bus.h>
44
45 #include <dev/bhnd/bhnd_erom.h>
46
47 #include <dev/bhnd/cores/chipc/chipcreg.h>
48
49 #include "sibareg.h"
50 #include "sibavar.h"
51
52 struct siba_erom;
53 struct siba_erom_io;
54
55
56 static int                      siba_eio_init(struct siba_erom_io *io,
57                                     struct bhnd_erom_io *eio, u_int ncores);
58
59 static uint32_t                 siba_eio_read_4(struct siba_erom_io *io,
60                                     u_int core_idx, bus_size_t offset);
61
62 static struct siba_core_id      siba_eio_read_core_id(struct siba_erom_io *io,
63                                     u_int core_idx, int unit);
64
65 static int                      siba_eio_read_chipid(struct siba_erom_io *io,
66                                     bus_addr_t enum_addr,
67                                     struct bhnd_chipid *cid);
68
69 /**
70  * SIBA EROM generic I/O context
71  */
72 struct siba_erom_io {
73         struct bhnd_erom_io     *eio;           /**< erom I/O callbacks */
74         bhnd_addr_t              base_addr;     /**< address of first core */
75         u_int                    ncores;        /**< core count */
76 };
77
78 /**
79  * SIBA EROM per-instance state.
80  */
81 struct siba_erom {
82         struct bhnd_erom        obj;
83         struct siba_erom_io     io;     /**< i/o context */
84 };
85
86 #define EROM_LOG(io, fmt, ...)  do {                            \
87         printf("%s: " fmt, __FUNCTION__, ##__VA_ARGS__);        \
88 } while(0)
89
90 /* SIBA implementation of BHND_EROM_PROBE() */
91 static int
92 siba_erom_probe(bhnd_erom_class_t *cls, struct bhnd_erom_io *eio,
93     const struct bhnd_chipid *hint, struct bhnd_chipid *cid)
94 {
95         struct siba_erom_io     io;
96         uint32_t                idreg;
97         int                     error;
98
99         /* Initialize I/O context, assuming at least the first core is mapped */
100         if ((error = siba_eio_init(&io, eio, 1)))
101                 return (error);
102
103         /* Try using the provided hint. */
104         if (hint != NULL) {
105                 struct siba_core_id sid;
106
107                 /* Validate bus type */
108                 if (hint->chip_type != BHND_CHIPTYPE_SIBA)
109                         return (ENXIO);
110
111                 /*
112                  * Verify the first core's IDHIGH/IDLOW identification.
113                  * 
114                  * The core must be a Broadcom core, but must *not* be
115                  * a chipcommon core; those shouldn't be hinted.
116                  *
117                  * The first core on EXTIF-equipped devices varies, but on the
118                  * BCM4710, it's a SDRAM core (0x803).
119                  */
120
121                 sid = siba_eio_read_core_id(&io, 0, 0);
122
123                 if (sid.core_info.vendor != BHND_MFGID_BCM)
124                         return (ENXIO);
125
126                 if (sid.core_info.device == BHND_COREID_CC)
127                         return (EINVAL);
128
129                 *cid = *hint;
130         } else {
131                 /* Validate bus type */
132                 idreg = siba_eio_read_4(&io, 0, CHIPC_ID);
133                 if (CHIPC_GET_BITS(idreg, CHIPC_ID_BUS) != BHND_CHIPTYPE_SIBA)
134                         return (ENXIO); 
135
136                 /* Identify the chipset */
137                 if ((error = siba_eio_read_chipid(&io, SIBA_ENUM_ADDR, cid)))
138                         return (error);
139
140                 /* Verify the chip type */
141                 if (cid->chip_type != BHND_CHIPTYPE_SIBA)
142                         return (ENXIO);
143         }
144
145         /*
146          * gcc hack: ensure bhnd_chipid.ncores cannot exceed SIBA_MAX_CORES
147          * without triggering build failure due to -Wtype-limits
148          *
149          * if (cid.ncores > SIBA_MAX_CORES)
150          *      return (EINVAL)
151          */
152         _Static_assert((2^sizeof(cid->ncores)) <= SIBA_MAX_CORES,
153             "ncores could result in over-read of backing resource");
154
155         return (0);
156 }
157
158 /* SIBA implementation of BHND_EROM_INIT() */
159 static int
160 siba_erom_init(bhnd_erom_t *erom, const struct bhnd_chipid *cid,
161     struct bhnd_erom_io *eio)
162 {
163         struct siba_erom        *sc;
164         int                      error;
165
166         sc = (struct siba_erom *)erom;
167
168         /* Attempt to map the full core enumeration space */
169         error = bhnd_erom_io_map(eio, cid->enum_addr,
170             cid->ncores * SIBA_CORE_SIZE);
171         if (error) {
172                 printf("%s: failed to map %u cores: %d\n", __FUNCTION__,
173                     cid->ncores, error);
174                 return (error);
175         }
176
177         /* Initialize I/O context */
178         return (siba_eio_init(&sc->io, eio, cid->ncores));
179 }
180
181 /* SIBA implementation of BHND_EROM_FINI() */
182 static void
183 siba_erom_fini(bhnd_erom_t *erom)
184 {
185         struct siba_erom *sc = (struct siba_erom *)erom;
186
187         bhnd_erom_io_fini(sc->io.eio);
188 }
189
190 /* Initialize siba_erom resource I/O context */
191 static int
192 siba_eio_init(struct siba_erom_io *io, struct bhnd_erom_io *eio, u_int ncores)
193 {
194         io->eio = eio;
195         io->ncores = ncores;
196         return (0);
197 }
198
199 /**
200  * Read a 32-bit value from @p offset relative to the base address of
201  * the given @p core_idx.
202  * 
203  * @param io EROM I/O context.
204  * @param core_idx Core index.
205  * @param offset Core register offset.
206  */
207 static uint32_t
208 siba_eio_read_4(struct siba_erom_io *io, u_int core_idx, bus_size_t offset)
209 {
210         /* Sanity check core index and offset */
211         if (core_idx >= io->ncores)
212                 panic("core index %u out of range (ncores=%u)", core_idx,
213                     io->ncores);
214
215         if (offset > SIBA_CORE_SIZE - sizeof(uint32_t))
216                 panic("invalid core offset %#jx", (uintmax_t)offset);
217
218         /* Perform read */
219         return (bhnd_erom_io_read(io->eio, SIBA_CORE_OFFSET(core_idx) + offset,
220             4));
221 }
222
223 /**
224  * Read and parse identification registers for the given @p core_index.
225  * 
226  * @param io EROM I/O context.
227  * @param core_idx The core index.
228  * @param unit The caller-specified unit number to be included in the return
229  * value.
230  */
231 static struct siba_core_id
232 siba_eio_read_core_id(struct siba_erom_io *io, u_int core_idx, int unit)
233 {
234         uint32_t idhigh, idlow;
235
236         idhigh = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
237         idlow = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_IDLOW));
238
239         return (siba_parse_core_id(idhigh, idlow, core_idx, unit));
240 }
241
242 /**
243  * Read and parse the chip identification register from the ChipCommon core.
244  * 
245  * @param io EROM I/O context.
246  * @param enum_addr The physical address mapped by @p io.
247  * @param cid On success, the parsed chip identifier.
248  */
249 static int
250 siba_eio_read_chipid(struct siba_erom_io *io, bus_addr_t enum_addr,
251     struct bhnd_chipid *cid)
252 {
253         struct siba_core_id     ccid;
254         uint32_t                idreg;
255
256         /* Identify the chipcommon core */
257         ccid = siba_eio_read_core_id(io, 0, 0);
258         if (ccid.core_info.vendor != BHND_MFGID_BCM ||
259             ccid.core_info.device != BHND_COREID_CC)
260         {
261                 if (bootverbose) {
262                         EROM_LOG(io, "first core not chipcommon "
263                             "(vendor=%#hx, core=%#hx)\n", ccid.core_info.vendor,
264                             ccid.core_info.device);
265                 }
266                 return (ENXIO);
267         }
268
269         /* Identify the chipset */
270         idreg = siba_eio_read_4(io, 0, CHIPC_ID);
271         *cid = bhnd_parse_chipid(idreg, enum_addr);
272
273         /* Fix up the core count in-place */
274         return (bhnd_chipid_fixed_ncores(cid, ccid.core_info.hwrev,
275             &cid->ncores));
276 }
277
278 static int
279 siba_erom_lookup_core(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
280     struct bhnd_core_info *core)
281 {
282         struct siba_erom        *sc;
283         struct bhnd_core_match   imatch;
284
285         sc = (struct siba_erom *)erom;
286
287         /* We can't determine a core's unit number during the initial scan. */
288         imatch = *desc;
289         imatch.m.match.core_unit = 0;
290
291         /* Locate the first matching core */
292         for (u_int i = 0; i < sc->io.ncores; i++) {
293                 struct siba_core_id     sid;
294                 struct bhnd_core_info   ci;
295
296                 /* Read the core info */
297                 sid = siba_eio_read_core_id(&sc->io, i, 0);
298                 ci = sid.core_info;
299
300                 /* Check for initial match */
301                 if (!bhnd_core_matches(&ci, &imatch))
302                         continue;
303
304                 /* Re-scan preceding cores to determine the unit number. */
305                 for (u_int j = 0; j < i; j++) {
306                         sid = siba_eio_read_core_id(&sc->io, j, 0);
307
308                         /* Bump the unit number? */
309                         if (sid.core_info.vendor == ci.vendor &&
310                             sid.core_info.device == ci.device)
311                                 ci.unit++;
312                 }
313
314                 /* Check for full match against now-valid unit number */
315                 if (!bhnd_core_matches(&ci, desc))
316                         continue;
317
318                 /* Matching core found */
319                 *core = ci;
320                 return (0);
321         }
322
323         /* Not found */
324         return (ENOENT);
325 }
326
327 static int
328 siba_erom_lookup_core_addr(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
329     bhnd_port_type type, u_int port, u_int region, struct bhnd_core_info *info,
330     bhnd_addr_t *addr, bhnd_size_t *size)
331 {
332         struct siba_erom        *sc;
333         struct bhnd_core_info    core;
334         struct siba_core_id      sid;
335         uint32_t                 am, am_addr, am_size;
336         u_int                    am_offset;
337         u_int                    addrspace, cfg;
338         
339         int                      error;
340
341         sc = (struct siba_erom *)erom;
342
343         /* Locate the requested core */
344         if ((error = siba_erom_lookup_core(erom, desc, &core)))
345                 return (error);
346
347         /* Fetch full siba core ident */
348         sid = siba_eio_read_core_id(&sc->io, core.core_idx, core.unit);
349
350         /* Is port valid? */
351         if (!siba_is_port_valid(&sid, type, port))
352                 return (ENOENT);
353
354         /* Is region valid? */
355         if (region >= siba_port_region_count(&sid, type, port))
356                 return (ENOENT);
357
358         /* Is this a siba configuration region? If so, this is mapped to an
359          * offset within the device0.0 port */
360         error = siba_cfg_index(&sid, type, port, region, &cfg);
361         if (!error) {
362                 bhnd_addr_t     region_addr;
363                 bhnd_addr_t     region_size;
364                 bhnd_size_t     cfg_offset, cfg_size;
365
366                 cfg_offset = SIBA_CFG_OFFSET(cfg);
367                 cfg_size = SIBA_CFG_SIZE;
368
369                 /* Fetch the device0.0 addr/size */
370                 error = siba_erom_lookup_core_addr(erom, desc, BHND_PORT_DEVICE,
371                     0, 0, NULL, &region_addr, &region_size);
372                 if (error)
373                         return (error);
374
375                 /* Verify that our offset fits within the region */
376                 if (region_size < cfg_size) {
377                         printf("%s%u.%u offset %ju exceeds %s0.0 size %ju\n",
378                             bhnd_port_type_name(type), port, region, cfg_offset,
379                             bhnd_port_type_name(BHND_PORT_DEVICE), region_size);
380
381                         return (ENXIO);
382                 }
383
384                 if (BHND_ADDR_MAX - region_addr < cfg_offset) {
385                         printf("%s%u.%u offset %ju would overflow %s0.0 addr "
386                             "%ju\n", bhnd_port_type_name(type), port, region,
387                             cfg_offset, bhnd_port_type_name(BHND_PORT_DEVICE),
388                             region_addr);
389
390                         return (ENXIO);
391                 }
392
393                 if (info != NULL)
394                         *info = core;
395
396                 *addr = region_addr + cfg_offset;
397                 *size = cfg_size;
398                 return (0);
399         }
400
401         /* 
402          * Otherwise, must be a device port.
403          * 
404          * Map the bhnd device port to a siba addrspace index. Unlike siba(4)
405          * bus drivers, we do not exclude the siba(4) configuration blocks from
406          * the first device port.
407          */
408         error = siba_addrspace_index(&sid, type, port, region, &addrspace);
409         if (error)
410                 return (error);
411
412         /* Determine the register offset */
413         am_offset = siba_admatch_offset(addrspace);
414         if (am_offset == 0) {
415                 printf("addrspace %u is unsupported", addrspace);
416                 return (ENODEV);
417         }
418
419         /* Read and parse the address match register */
420         am = siba_eio_read_4(&sc->io, core.core_idx, am_offset);
421
422         if ((error = siba_parse_admatch(am, &am_addr, &am_size))) {
423                 printf("failed to decode address match register value 0x%x\n",
424                     am);
425                 return (error);
426         }
427
428         if (info != NULL)
429                 *info = core;
430
431         *addr = am_addr;
432         *size = am_size;
433
434         return (0);
435 }
436
437 /* BHND_EROM_GET_CORE_TABLE() */
438 static int
439 siba_erom_get_core_table(bhnd_erom_t *erom, struct bhnd_core_info **cores,
440     u_int *num_cores)
441 {
442         struct siba_erom        *sc;
443         struct bhnd_core_info   *out;
444
445         sc = (struct siba_erom *)erom;
446
447         /* Allocate our core array */
448         out = malloc(sizeof(*out) * sc->io.ncores, M_BHND, M_NOWAIT);
449         if (out == NULL)
450                 return (ENOMEM);
451
452         *cores = out;
453         *num_cores = sc->io.ncores;
454
455         /* Enumerate all cores. */
456         for (u_int i = 0; i < sc->io.ncores; i++) {
457                 struct siba_core_id sid;
458
459                 /* Read the core info */
460                 sid = siba_eio_read_core_id(&sc->io, i, 0);
461                 out[i] = sid.core_info;
462
463                 /* Determine unit number */
464                 for (u_int j = 0; j < i; j++) {
465                         if (out[j].vendor == out[i].vendor &&
466                             out[j].device == out[i].device)
467                                 out[i].unit++;
468                 }
469         }
470
471         return (0);
472 }
473
474 /* BHND_EROM_FREE_CORE_TABLE() */
475 static void
476 siba_erom_free_core_table(bhnd_erom_t *erom, struct bhnd_core_info *cores)
477 {
478         free(cores, M_BHND);
479 }
480
481 /* BHND_EROM_DUMP() */
482 static int
483 siba_erom_dump(bhnd_erom_t *erom)
484 {
485         struct siba_erom        *sc;
486         int                      error;
487
488         sc = (struct siba_erom *)erom;
489
490         /* Enumerate all cores. */
491         for (u_int i = 0; i < sc->io.ncores; i++) {
492                 uint32_t idhigh, idlow;
493                 uint32_t nraddr;
494
495                 idhigh = siba_eio_read_4(&sc->io, i,
496                     SB0_REG_ABS(SIBA_CFG0_IDHIGH));
497                 idlow = siba_eio_read_4(&sc->io, i,
498                     SB0_REG_ABS(SIBA_CFG0_IDLOW));
499
500                 printf("siba core %u:\n", i);
501                 printf("\tvendor:\t0x%04x\n", SIBA_REG_GET(idhigh, IDH_VENDOR));
502                 printf("\tdevice:\t0x%04x\n", SIBA_REG_GET(idhigh, IDH_DEVICE));
503                 printf("\trev:\t0x%04x\n", SIBA_IDH_CORE_REV(idhigh));
504                 printf("\tsbrev:\t0x%02x\n", SIBA_REG_GET(idlow, IDL_SBREV));
505
506                 /* Enumerate the address match registers */
507                 nraddr = SIBA_REG_GET(idlow, IDL_NRADDR);
508                 printf("\tnraddr\t0x%04x\n", nraddr);
509
510                 for (size_t addrspace = 0; addrspace < nraddr; addrspace++) {
511                         uint32_t        am, am_addr, am_size;
512                         u_int           am_offset;
513
514                         /* Determine the register offset */
515                         am_offset = siba_admatch_offset(addrspace);
516                         if (am_offset == 0) {
517                                 printf("addrspace %zu unsupported",
518                                     addrspace);
519                                 break;
520                         }
521                         
522                         /* Read and parse the address match register */
523                         am = siba_eio_read_4(&sc->io, i, am_offset);
524                         error = siba_parse_admatch(am, &am_addr, &am_size);
525                         if (error) {
526                                 printf("failed to decode address match "
527                                     "register value 0x%x\n", am);
528                                 continue;
529                         }
530
531                         printf("\taddrspace %zu\n", addrspace);
532                         printf("\t\taddr: 0x%08x\n", am_addr);
533                         printf("\t\tsize: 0x%08x\n", am_size);
534                 }
535         }
536
537         return (0);
538 }
539
540 static kobj_method_t siba_erom_methods[] = {
541         KOBJMETHOD(bhnd_erom_probe,             siba_erom_probe),
542         KOBJMETHOD(bhnd_erom_init,              siba_erom_init),
543         KOBJMETHOD(bhnd_erom_fini,              siba_erom_fini),
544         KOBJMETHOD(bhnd_erom_get_core_table,    siba_erom_get_core_table),
545         KOBJMETHOD(bhnd_erom_free_core_table,   siba_erom_free_core_table),
546         KOBJMETHOD(bhnd_erom_lookup_core,       siba_erom_lookup_core),
547         KOBJMETHOD(bhnd_erom_lookup_core_addr,  siba_erom_lookup_core_addr),
548         KOBJMETHOD(bhnd_erom_dump,              siba_erom_dump),
549
550         KOBJMETHOD_END
551 };
552
553 BHND_EROM_DEFINE_CLASS(siba_erom, siba_erom_parser, siba_erom_methods, sizeof(struct siba_erom));