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