1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2016 Michael Zhilin <mizhka@gmail.com>
5 * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
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 * without modification.
14 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
15 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
16 * redistribution must be conditioned upon including a substantially
17 * similar Disclaimer requirement for further binary redistribution.
18 *
19 * NO WARRANTY
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
23 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
24 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
25 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
28 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGES.
31 */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <sys/param.h>
37 #include <sys/kernel.h>
38
39 #include "chipc_private.h"
40 #include "chipcvar.h"
41
42 /**
43 * Return a human-readable name for the given flash @p type.
44 */
45 const char *
46 chipc_flash_name(chipc_flash type)
47 {
48 switch (type) {
49 case CHIPC_PFLASH_CFI:
50 return ("CFI Flash");
51
52 case CHIPC_SFLASH_ST:
53 case CHIPC_SFLASH_AT:
54 return ("SPI Flash");
55
56 case CHIPC_QSFLASH_ST:
57 case CHIPC_QSFLASH_AT:
58 return ("QSPI Flash");
59
60 case CHIPC_NFLASH:
61 case CHIPC_NFLASH_4706:
62 return ("NAND");
63
64 case CHIPC_FLASH_NONE:
65 default:
66 return ("unknown");
67 }
68 }
69
70 /**
71 * Return the name of the bus device class used by flash @p type,
72 * or NULL if @p type is unsupported.
73 */
74 const char *
75 chipc_flash_bus_name(chipc_flash type)
76 {
77 switch (type) {
78 case CHIPC_PFLASH_CFI:
79 return ("cfi");
80
81 case CHIPC_SFLASH_ST:
82 case CHIPC_SFLASH_AT:
83 return ("spi");
84
85 case CHIPC_QSFLASH_ST:
86 case CHIPC_QSFLASH_AT:
87 /* unimplemented; spi? */
88 return (NULL);
89
90 case CHIPC_NFLASH:
91 case CHIPC_NFLASH_4706:
92 /* unimplemented; nandbus? */
93 return (NULL);
94
95 case CHIPC_FLASH_NONE:
96 default:
97 return (NULL);
98 }
99 }
100
101 /**
102 * Return the name of the flash device class for SPI flash @p type,
103 * or NULL if @p type does not use SPI, or is unsupported.
104 */
105 const char *
106 chipc_sflash_device_name(chipc_flash type)
107 {
108 switch (type) {
109 case CHIPC_SFLASH_ST:
110 return ("mx25l");
111
112 case CHIPC_SFLASH_AT:
113 return ("at45d");
114
115 case CHIPC_QSFLASH_ST:
116 case CHIPC_QSFLASH_AT:
117 /* unimplemented */
118 return (NULL);
119
120 case CHIPC_PFLASH_CFI:
121 case CHIPC_NFLASH:
122 case CHIPC_NFLASH_4706:
123 case CHIPC_FLASH_NONE:
124 default:
125 return (NULL);
126 }
127 }
128
129 /**
130 * Initialize child resource @p r with a virtual address, tag, and handle
131 * copied from @p parent, adjusted to contain only the range defined by
132 * @p offsize and @p size.
133 *
134 * @param r The register to be initialized.
135 * @param parent The parent bus resource that fully contains the subregion.
136 * @param offset The subregion offset within @p parent.
137 * @param size The subregion size.
138 */
139 int
140 chipc_init_child_resource(struct resource *r,
141 struct resource *parent, bhnd_size_t offset, bhnd_size_t size)
142 {
143 bus_space_handle_t bh, child_bh;
144 bus_space_tag_t bt;
145 uintptr_t vaddr;
146 int error;
147
148 /* Fetch the parent resource's bus values */
149 vaddr = (uintptr_t) rman_get_virtual(parent);
150 bt = rman_get_bustag(parent);
151 bh = rman_get_bushandle(parent);
152
153 /* Configure child resource with offset-adjusted values */
154 vaddr += offset;
155 error = bus_space_subregion(bt, bh, offset, size, &child_bh);
156 if (error)
157 return (error);
158
159 rman_set_virtual(r, (void *) vaddr);
160 rman_set_bustag(r, bt);
161 rman_set_bushandle(r, child_bh);
162
163 return (0);
164 }
165
166 /**
167 * Map an interrupt line to an IRQ, and then register a corresponding SYS_RES_IRQ
168 * with @p child's resource list.
169 *
170 * @param sc chipc driver state.
171 * @param child The device to set the resource on.
172 * @param rid The resource ID.
173 * @param intr The interrupt line to be mapped.
174 * @param count The length of the resource.
175 * @param port The mapping port number (ignored if not SYS_RES_MEMORY).
176 * @param region The mapping region number (ignored if not SYS_RES_MEMORY).
177 */
178 int
179 chipc_set_irq_resource(struct chipc_softc *sc, device_t child, int rid,
180 u_int intr)
181 {
182 struct chipc_devinfo *dinfo;
183 int error;
184
185 KASSERT(device_get_parent(child) == sc->dev, ("not a direct child"));
186 dinfo = device_get_ivars(child);
187
188 /* We currently only support a single IRQ mapping */
189 if (dinfo->irq_mapped) {
190 device_printf(sc->dev, "irq already mapped for child\n");
191 return (ENOMEM);
192 }
193
194 /* Map the IRQ */
195 if ((error = bhnd_map_intr(sc->dev, intr, &dinfo->irq))) {
196 device_printf(sc->dev, "failed to map intr %u: %d\n", intr,
197 error);
198 return (error);
199 }
200
201 dinfo->irq_mapped = true;
202
203 /* Add to child's resource list */
204 error = bus_set_resource(child, SYS_RES_IRQ, rid, dinfo->irq, 1);
205 if (error) {
206 device_printf(sc->dev, "failed to set child irq resource %d to "
207 "%ju: %d\n", rid, dinfo->irq, error);
208
209 bhnd_unmap_intr(sc->dev, dinfo->irq);
210 return (error);
211 }
212
213 return (0);
214 }
215
216 /**
217 * Add a SYS_RES_MEMORY resource with a given resource ID, relative to the
218 * given port and region, to @p child's resource list.
219 *
220 * The specified @p region's address and size will be fetched from the bhnd(4)
221 * bus, and bus_set_resource() will be called with @p start added the region's
222 * actual base address.
223 *
224 * To use the default region values for @p start and @p count, specify
225 * a @p start value of 0ul, and an end value of RMAN_MAX_END
226 *
227 * @param sc chipc driver state.
228 * @param child The device to set the resource on.
229 * @param rid The resource ID.
230 * @param start The resource start address (if SYS_RES_MEMORY, this is
231 * relative to @p region's base address).
232 * @param count The length of the resource.
233 * @param port The mapping port number (ignored if not SYS_RES_MEMORY).
234 * @param region The mapping region number (ignored if not SYS_RES_MEMORY).
235 */
236 int
237 chipc_set_mem_resource(struct chipc_softc *sc, device_t child, int rid,
238 rman_res_t start, rman_res_t count, u_int port, u_int region)
239 {
240 bhnd_addr_t region_addr;
241 bhnd_size_t region_size;
242 bool isdefault;
243 int error;
244
245 KASSERT(device_get_parent(child) == sc->dev, ("not a direct child"));
246 isdefault = RMAN_IS_DEFAULT_RANGE(start, count);
247
248 /* Fetch region address and size */
249 error = bhnd_get_region_addr(sc->dev, BHND_PORT_DEVICE, port,
250 region, ®ion_addr, ®ion_size);
251 if (error) {
252 device_printf(sc->dev,
253 "lookup of %s%u.%u failed: %d\n",
254 bhnd_port_type_name(BHND_PORT_DEVICE), port, region, error);
255 return (error);
256 }
257
258 /* Populate defaults */
259 if (isdefault) {
260 start = 0;
261 count = region_size;
262 }
263
264 /* Verify requested range is mappable */
265 if (start > region_size || region_size - start < count) {
266 device_printf(sc->dev,
267 "%s%u.%u region cannot map requested range %#jx+%#jx\n",
268 bhnd_port_type_name(BHND_PORT_DEVICE), port, region, start,
269 count);
270 return (ERANGE);
271 }
272
273 return (bus_set_resource(child, SYS_RES_MEMORY, rid,
274 region_addr + start, count));
275 }
276
277 /*
278 * Print a capability structure.
279 */
280 void
281 chipc_print_caps(device_t dev, struct chipc_caps *caps)
282 {
283 #define CC_TFS(_flag) (caps->_flag ? "yes" : "no")
284
285 device_printf(dev, "MIPSEB: %-3s | BP64: %s\n",
286 CC_TFS(mipseb), CC_TFS(backplane_64));
287 device_printf(dev, "UARTs: %-3hhu | UGPIO: %s\n",
288 caps->num_uarts, CC_TFS(uart_gpio));
289 // XXX: hitting a kvprintf bug with '%#02x' not prefixing '0x' in
290 // some cases, and not apply the field width in others
291 device_printf(dev, "UARTClk: 0x%02x | Flash: %u\n",
292 caps->uart_clock, caps->flash_type);
293 device_printf(dev, "SPROM: %-3s | OTP: %s\n",
294 CC_TFS(sprom), CC_TFS(otp_size));
295 device_printf(dev, "CFIsz: 0x%02x | OTPsz: 0x%02x\n",
296 caps->cfi_width, caps->otp_size);
297 device_printf(dev, "ExtBus: 0x%02x | PwrCtrl: %s\n",
298 caps->extbus_type, CC_TFS(pwr_ctrl));
299 device_printf(dev, "PLL: 0x%02x | JTAGM: %s\n",
300 caps->pll_type, CC_TFS(jtag_master));
301 device_printf(dev, "PMU: %-3s | ECI: %s\n",
302 CC_TFS(pmu), CC_TFS(eci));
303 device_printf(dev, "SECI: %-3s | GSIO: %s\n",
304 CC_TFS(seci), CC_TFS(gsio));
305 device_printf(dev, "AOB: %-3s | BootROM: %s\n",
306 CC_TFS(aob), CC_TFS(boot_rom));
307
308 #undef CC_TFS
309 }
310
311 /**
312 * Allocate and initialize new region record.
313 *
314 * @param sc Driver instance state.
315 * @param type The port type to query.
316 * @param port The port number to query.
317 * @param region The region number to query.
318 */
319 struct chipc_region *
320 chipc_alloc_region(struct chipc_softc *sc, bhnd_port_type type,
321 u_int port, u_int region)
322 {
323 struct chipc_region *cr;
324 int error;
325
326 /* Don't bother allocating a chipc_region if init will fail */
327 if (!bhnd_is_region_valid(sc->dev, type, port, region))
328 return (NULL);
329
330 /* Allocate and initialize region info */
331 cr = malloc(sizeof(*cr), M_BHND, M_NOWAIT);
332 if (cr == NULL)
333 return (NULL);
334
335 cr->cr_port_type = type;
336 cr->cr_port_num = port;
337 cr->cr_region_num = region;
338 cr->cr_res = NULL;
339 cr->cr_refs = 0;
340 cr->cr_act_refs = 0;
341
342 error = bhnd_get_region_addr(sc->dev, type, port, region, &cr->cr_addr,
343 &cr->cr_count);
344 if (error) {
345 device_printf(sc->dev,
346 "fetching chipc region address failed: %d\n", error);
347 goto failed;
348 }
349
350 cr->cr_end = cr->cr_addr + cr->cr_count - 1;
351
352 /* Fetch default resource ID for this region. Not all regions have an
353 * assigned rid, in which case this will return -1 */
354 cr->cr_rid = bhnd_get_port_rid(sc->dev, type, port, region);
355
356 return (cr);
357
358 failed:
359 device_printf(sc->dev, "chipc region alloc failed for %s%u.%u\n",
360 bhnd_port_type_name(type), port, region);
361 free(cr, M_BHND);
362 return (NULL);
363 }
364
365 /**
366 * Deallocate the given region record and its associated resource, if any.
367 *
368 * @param sc Driver instance state.
369 * @param cr Region record to be deallocated.
370 */
371 void
372 chipc_free_region(struct chipc_softc *sc, struct chipc_region *cr)
373 {
374 KASSERT(cr->cr_refs == 0,
375 ("chipc %s%u.%u region has %u active references",
376 bhnd_port_type_name(cr->cr_port_type), cr->cr_port_num,
377 cr->cr_region_num, cr->cr_refs));
378
379 if (cr->cr_res != NULL) {
380 bhnd_release_resource(sc->dev, SYS_RES_MEMORY, cr->cr_res_rid,
381 cr->cr_res);
382 }
383
384 free(cr, M_BHND);
385 }
386
387 /**
388 * Locate the region mapping the given range, if any. Returns NULL if no
389 * valid region is found.
390 *
391 * @param sc Driver instance state.
392 * @param start start of address range.
393 * @param end end of address range.
394 */
395 struct chipc_region *
396 chipc_find_region(struct chipc_softc *sc, rman_res_t start, rman_res_t end)
397 {
398 struct chipc_region *cr;
399
400 if (start > end)
401 return (NULL);
402
403 STAILQ_FOREACH(cr, &sc->mem_regions, cr_link) {
404 if (start < cr->cr_addr || end > cr->cr_end)
405 continue;
406
407 /* Found */
408 return (cr);
409 }
410
411 /* Not found */
412 return (NULL);
413 }
414
415 /**
416 * Locate a region mapping by its bhnd-assigned resource id (as returned by
417 * bhnd_get_port_rid).
418 *
419 * @param sc Driver instance state.
420 * @param rid Resource ID to query for.
421 */
422 struct chipc_region *
423 chipc_find_region_by_rid(struct chipc_softc *sc, int rid)
424 {
425 struct chipc_region *cr;
426 int port_rid;
427
428 STAILQ_FOREACH(cr, &sc->mem_regions, cr_link) {
429 port_rid = bhnd_get_port_rid(sc->dev, cr->cr_port_type,
430 cr->cr_port_num, cr->cr_region_num);
431 if (port_rid == -1 || port_rid != rid)
432 continue;
433
434 /* Found */
435 return (cr);
436 }
437
438 /* Not found */
439 return (NULL);
440 }
441
442 /**
443 * Retain a reference to a chipc_region, allocating and activating the
444 * backing resource as required.
445 *
446 * @param sc chipc driver instance state
447 * @param cr region to retain.
448 * @param flags specify RF_ALLOCATED to retain an allocation reference,
449 * RF_ACTIVE to retain an activation reference.
450 */
451 int
452 chipc_retain_region(struct chipc_softc *sc, struct chipc_region *cr, int flags)
453 {
454 int error;
455
456 KASSERT(!(flags &~ (RF_ACTIVE|RF_ALLOCATED)), ("unsupported flags"));
457
458 CHIPC_LOCK(sc);
459
460 /* Handle allocation */
461 if (flags & RF_ALLOCATED) {
462 /* If this is the first reference, allocate the resource */
463 if (cr->cr_refs == 0) {
464 KASSERT(cr->cr_res == NULL,
465 ("non-NULL resource has refcount"));
466
467 /* Fetch initial resource ID */
468 if ((cr->cr_res_rid = cr->cr_rid) == -1) {
469 CHIPC_UNLOCK(sc);
470 return (EINVAL);
471 }
472
473 /* Allocate resource */
474 cr->cr_res = bhnd_alloc_resource(sc->dev,
475 SYS_RES_MEMORY, &cr->cr_res_rid, cr->cr_addr,
476 cr->cr_end, cr->cr_count, RF_SHAREABLE);
477 if (cr->cr_res == NULL) {
478 CHIPC_UNLOCK(sc);
479 return (ENXIO);
480 }
481 }
482
483 /* Increment allocation refcount */
484 cr->cr_refs++;
485 }
486
487 /* Handle activation */
488 if (flags & RF_ACTIVE) {
489 KASSERT(cr->cr_refs > 0,
490 ("cannot activate unallocated resource"));
491
492 /* If this is the first reference, activate the resource */
493 if (cr->cr_act_refs == 0) {
494 error = bhnd_activate_resource(sc->dev, SYS_RES_MEMORY,
495 cr->cr_res_rid, cr->cr_res);
496 if (error) {
497 /* Drop any allocation reference acquired
498 * above */
499 CHIPC_UNLOCK(sc);
500 chipc_release_region(sc, cr,
501 flags &~ RF_ACTIVE);
502 return (error);
503 }
504 }
505
506 /* Increment activation refcount */
507 cr->cr_act_refs++;
508 }
509
510 CHIPC_UNLOCK(sc);
511 return (0);
512 }
513
514 /**
515 * Release a reference to a chipc_region, deactivating and releasing the
516 * backing resource if the reference count hits zero.
517 *
518 * @param sc chipc driver instance state
519 * @param cr region to retain.
520 * @param flags specify RF_ALLOCATED to release an allocation reference,
521 * RF_ACTIVE to release an activation reference.
522 */
523 int
524 chipc_release_region(struct chipc_softc *sc, struct chipc_region *cr,
525 int flags)
526 {
527 int error;
528
529 CHIPC_LOCK(sc);
530 error = 0;
531
532 KASSERT(cr->cr_res != NULL, ("release on NULL region resource"));
533
534 if (flags & RF_ACTIVE) {
535 KASSERT(cr->cr_act_refs > 0, ("RF_ACTIVE over-released"));
536 KASSERT(cr->cr_act_refs <= cr->cr_refs,
537 ("RF_ALLOCATED released with RF_ACTIVE held"));
538
539 /* If this is the last reference, deactivate the resource */
540 if (cr->cr_act_refs == 1) {
541 error = bhnd_deactivate_resource(sc->dev,
542 SYS_RES_MEMORY, cr->cr_res_rid, cr->cr_res);
543 if (error)
544 goto done;
545 }
546
547 /* Drop our activation refcount */
548 cr->cr_act_refs--;
549 }
550
551 if (flags & RF_ALLOCATED) {
552 KASSERT(cr->cr_refs > 0, ("overrelease of refs"));
553 /* If this is the last reference, release the resource */
554 if (cr->cr_refs == 1) {
555 error = bhnd_release_resource(sc->dev, SYS_RES_MEMORY,
556 cr->cr_res_rid, cr->cr_res);
557 if (error)
558 goto done;
559
560 cr->cr_res = NULL;
561 }
562
563 /* Drop our allocation refcount */
564 cr->cr_refs--;
565 }
566
567 done:
568 CHIPC_UNLOCK(sc);
569 return (error);
570 }
Cache object: 054bae5a28d744d4484e80e58780e431
|