2 * Copyright (c) 2016 Michael Zhilin <mizhka@gmail.com>
3 * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer,
11 * without modification.
12 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
13 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
14 * redistribution must be conditioned upon including a substantially
15 * similar Disclaimer requirement for further binary redistribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
21 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
23 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
26 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGES.
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
35 #include <sys/kernel.h>
37 #include "chipc_private.h"
41 * Return a human-readable name for the given flash @p type.
44 chipc_flash_name(chipc_flash type)
47 case CHIPC_PFLASH_CFI:
54 case CHIPC_QSFLASH_ST:
55 case CHIPC_QSFLASH_AT:
56 return ("QSPI Flash");
59 case CHIPC_NFLASH_4706:
62 case CHIPC_FLASH_NONE:
69 * Return the name of the bus device class used by flash @p type,
70 * or NULL if @p type is unsupported.
73 chipc_flash_bus_name(chipc_flash type)
76 case CHIPC_PFLASH_CFI:
83 case CHIPC_QSFLASH_ST:
84 case CHIPC_QSFLASH_AT:
85 /* unimplemented; spi? */
89 case CHIPC_NFLASH_4706:
90 /* unimplemented; nandbus? */
93 case CHIPC_FLASH_NONE:
100 * Return the name of the flash device class for SPI flash @p type,
101 * or NULL if @p type does not use SPI, or is unsupported.
104 chipc_sflash_device_name(chipc_flash type)
107 case CHIPC_SFLASH_ST:
110 case CHIPC_SFLASH_AT:
113 case CHIPC_QSFLASH_ST:
114 case CHIPC_QSFLASH_AT:
118 case CHIPC_PFLASH_CFI:
120 case CHIPC_NFLASH_4706:
121 case CHIPC_FLASH_NONE:
128 * Initialize child resource @p r with a virtual address, tag, and handle
129 * copied from @p parent, adjusted to contain only the range defined by
130 * @p offsize and @p size.
132 * @param r The register to be initialized.
133 * @param parent The parent bus resource that fully contains the subregion.
134 * @param offset The subregion offset within @p parent.
135 * @param size The subregion size.
138 chipc_init_child_resource(struct resource *r,
139 struct resource *parent, bhnd_size_t offset, bhnd_size_t size)
141 bus_space_handle_t bh, child_bh;
146 /* Fetch the parent resource's bus values */
147 vaddr = (uintptr_t) rman_get_virtual(parent);
148 bt = rman_get_bustag(parent);
149 bh = rman_get_bushandle(parent);
151 /* Configure child resource with offset-adjusted values */
153 error = bus_space_subregion(bt, bh, offset, size, &child_bh);
157 rman_set_virtual(r, (void *) vaddr);
158 rman_set_bustag(r, bt);
159 rman_set_bushandle(r, child_bh);
165 * Associate a resource with a given resource ID, relative to the given
168 * This function behaves identically to bus_set_resource() for all resource
169 * types other than SYS_RES_MEMORY.
171 * For SYS_RES_MEMORY resources, the specified @p region's address and size
172 * will be fetched from the bhnd(4) bus, and bus_set_resource() will be called
173 * with @p start added the region's actual base address.
175 * To use the default region values for @p start and @p count, specify
176 * a @p start value of 0ul, and an end value of RMAN_MAX_END
178 * @param sc chipc driver state.
179 * @param child The device to set the resource on.
180 * @param type The resource type.
181 * @param rid The resource ID.
182 * @param start The resource start address (if SYS_RES_MEMORY, this is
183 * relative to @p region's base address).
184 * @param count The length of the resource.
185 * @param port The mapping port number (ignored if not SYS_RES_MEMORY).
186 * @param region The mapping region number (ignored if not SYS_RES_MEMORY).
189 chipc_set_resource(struct chipc_softc *sc, device_t child, int type, int rid,
190 rman_res_t start, rman_res_t count, u_int port, u_int region)
192 bhnd_addr_t region_addr;
193 bhnd_size_t region_size;
197 if (type != SYS_RES_MEMORY)
198 return (bus_set_resource(child, type, rid, start, count));
200 isdefault = RMAN_IS_DEFAULT_RANGE(start, count);
202 /* Fetch region address and size */
203 error = bhnd_get_region_addr(sc->dev, BHND_PORT_DEVICE, port,
204 region, ®ion_addr, ®ion_size);
206 device_printf(sc->dev,
207 "lookup of %s%u.%u failed: %d\n",
208 bhnd_port_type_name(BHND_PORT_DEVICE), port, region, error);
212 /* Populate defaults */
218 /* Verify requested range is mappable */
219 if (start > region_size || region_size - start < count) {
220 device_printf(sc->dev,
221 "%s%u.%u region cannot map requested range %#jx+%#jx\n",
222 bhnd_port_type_name(BHND_PORT_DEVICE), port, region, start,
227 return (bus_set_resource(child, type, rid, region_addr + start, count));
232 * Print a capability structure.
235 chipc_print_caps(device_t dev, struct chipc_caps *caps)
237 #define CC_TFS(_flag) (caps->_flag ? "yes" : "no")
239 device_printf(dev, "MIPSEB: %-3s | BP64: %s\n",
240 CC_TFS(mipseb), CC_TFS(backplane_64));
241 device_printf(dev, "UARTs: %-3hhu | UGPIO: %s\n",
242 caps->num_uarts, CC_TFS(uart_gpio));
243 // XXX: hitting a kvprintf bug with '%#02x' not prefixing '0x' in
244 // some cases, and not apply the field width in others
245 device_printf(dev, "UARTClk: 0x%02x | Flash: %u\n",
246 caps->uart_clock, caps->flash_type);
247 device_printf(dev, "SPROM: %-3s | OTP: %s\n",
248 CC_TFS(sprom), CC_TFS(otp_size));
249 device_printf(dev, "CFIsz: 0x%02x | OTPsz: 0x%02x\n",
250 caps->cfi_width, caps->otp_size);
251 device_printf(dev, "ExtBus: 0x%02x | PwrCtrl: %s\n",
252 caps->extbus_type, CC_TFS(pwr_ctrl));
253 device_printf(dev, "PLL: 0x%02x | JTAGM: %s\n",
254 caps->pll_type, CC_TFS(jtag_master));
255 device_printf(dev, "PMU: %-3s | ECI: %s\n",
256 CC_TFS(pmu), CC_TFS(eci));
257 device_printf(dev, "SECI: %-3s | GSIO: %s\n",
258 CC_TFS(seci), CC_TFS(gsio));
259 device_printf(dev, "AOB: %-3s | BootROM: %s\n",
260 CC_TFS(aob), CC_TFS(boot_rom));
266 * Allocate and initialize new region record.
268 * @param sc Driver instance state.
269 * @param type The port type to query.
270 * @param port The port number to query.
271 * @param region The region number to query.
273 struct chipc_region *
274 chipc_alloc_region(struct chipc_softc *sc, bhnd_port_type type,
275 u_int port, u_int region)
277 struct chipc_region *cr;
280 /* Don't bother allocating a chipc_region if init will fail */
281 if (!bhnd_is_region_valid(sc->dev, type, port, region))
284 /* Allocate and initialize region info */
285 cr = malloc(sizeof(*cr), M_BHND, M_NOWAIT);
289 cr->cr_port_type = type;
290 cr->cr_port_num = port;
291 cr->cr_region_num = region;
296 error = bhnd_get_region_addr(sc->dev, type, port, region, &cr->cr_addr,
299 device_printf(sc->dev,
300 "fetching chipc region address failed: %d\n", error);
304 cr->cr_end = cr->cr_addr + cr->cr_count - 1;
306 /* Fetch default resource ID for this region. Not all regions have an
307 * assigned rid, in which case this will return -1 */
308 cr->cr_rid = bhnd_get_port_rid(sc->dev, type, port, region);
313 device_printf(sc->dev, "chipc region alloc failed for %s%u.%u\n",
314 bhnd_port_type_name(type), port, region);
320 * Deallocate the given region record and its associated resource, if any.
322 * @param sc Driver instance state.
323 * @param cr Region record to be deallocated.
326 chipc_free_region(struct chipc_softc *sc, struct chipc_region *cr)
328 KASSERT(cr->cr_refs == 0,
329 ("chipc %s%u.%u region has %u active references",
330 bhnd_port_type_name(cr->cr_port_type), cr->cr_port_num,
331 cr->cr_region_num, cr->cr_refs));
333 if (cr->cr_res != NULL) {
334 bhnd_release_resource(sc->dev, SYS_RES_MEMORY, cr->cr_res_rid,
342 * Locate the region mapping the given range, if any. Returns NULL if no
343 * valid region is found.
345 * @param sc Driver instance state.
346 * @param start start of address range.
347 * @param end end of address range.
349 struct chipc_region *
350 chipc_find_region(struct chipc_softc *sc, rman_res_t start, rman_res_t end)
352 struct chipc_region *cr;
357 STAILQ_FOREACH(cr, &sc->mem_regions, cr_link) {
358 if (start < cr->cr_addr || end > cr->cr_end)
370 * Locate a region mapping by its bhnd-assigned resource id (as returned by
371 * bhnd_get_port_rid).
373 * @param sc Driver instance state.
374 * @param rid Resource ID to query for.
376 struct chipc_region *
377 chipc_find_region_by_rid(struct chipc_softc *sc, int rid)
379 struct chipc_region *cr;
382 STAILQ_FOREACH(cr, &sc->mem_regions, cr_link) {
383 port_rid = bhnd_get_port_rid(sc->dev, cr->cr_port_type,
384 cr->cr_port_num, cr->cr_region_num);
385 if (port_rid == -1 || port_rid != rid)
397 * Retain a reference to a chipc_region, allocating and activating the
398 * backing resource as required.
400 * @param sc chipc driver instance state
401 * @param cr region to retain.
402 * @param flags specify RF_ALLOCATED to retain an allocation reference,
403 * RF_ACTIVE to retain an activation reference.
406 chipc_retain_region(struct chipc_softc *sc, struct chipc_region *cr, int flags)
410 KASSERT(!(flags &~ (RF_ACTIVE|RF_ALLOCATED)), ("unsupported flags"));
414 /* Handle allocation */
415 if (flags & RF_ALLOCATED) {
416 /* If this is the first reference, allocate the resource */
417 if (cr->cr_refs == 0) {
418 KASSERT(cr->cr_res == NULL,
419 ("non-NULL resource has refcount"));
421 /* Fetch initial resource ID */
422 if ((cr->cr_res_rid = cr->cr_rid) == -1) {
427 /* Allocate resource */
428 cr->cr_res = bhnd_alloc_resource(sc->dev,
429 SYS_RES_MEMORY, &cr->cr_res_rid, cr->cr_addr,
430 cr->cr_end, cr->cr_count, 0);
431 if (cr->cr_res == NULL) {
437 /* Increment allocation refcount */
442 /* Handle activation */
443 if (flags & RF_ACTIVE) {
444 KASSERT(cr->cr_refs > 0,
445 ("cannot activate unallocated resource"));
447 /* If this is the first reference, activate the resource */
448 if (cr->cr_act_refs == 0) {
449 error = bhnd_activate_resource(sc->dev, SYS_RES_MEMORY,
450 cr->cr_res_rid, cr->cr_res);
452 /* Drop any allocation reference acquired
455 chipc_release_region(sc, cr,
461 /* Increment activation refcount */
470 * Release a reference to a chipc_region, deactivating and releasing the
471 * backing resource if the reference count hits zero.
473 * @param sc chipc driver instance state
474 * @param cr region to retain.
475 * @param flags specify RF_ALLOCATED to release an allocation reference,
476 * RF_ACTIVE to release an activation reference.
479 chipc_release_region(struct chipc_softc *sc, struct chipc_region *cr,
487 KASSERT(cr->cr_res != NULL, ("release on NULL region resource"));
489 if (flags & RF_ACTIVE) {
490 KASSERT(cr->cr_act_refs > 0, ("RF_ACTIVE over-released"));
491 KASSERT(cr->cr_act_refs <= cr->cr_refs,
492 ("RF_ALLOCATED released with RF_ACTIVE held"));
494 /* If this is the last reference, deactivate the resource */
495 if (cr->cr_act_refs == 1) {
496 error = bhnd_deactivate_resource(sc->dev,
497 SYS_RES_MEMORY, cr->cr_res_rid, cr->cr_res);
502 /* Drop our activation refcount */
506 if (flags & RF_ALLOCATED) {
507 KASSERT(cr->cr_refs > 0, ("overrelease of refs"));
508 /* If this is the last reference, release the resource */
509 if (cr->cr_refs == 1) {
510 error = bhnd_release_resource(sc->dev, SYS_RES_MEMORY,
511 cr->cr_res_rid, cr->cr_res);
518 /* Drop our allocation refcount */