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