xref: /freebsd/sys/dev/syscon/syscon.c (revision 62e8ccc3)
162e8ccc3SEmmanuel Vadot /*-
262e8ccc3SEmmanuel Vadot  * SPDX-License-Identifier: BSD-2-Clause
362e8ccc3SEmmanuel Vadot  *
462e8ccc3SEmmanuel Vadot  * Copyright (c) 2017 Kyle Evans <kevans@FreeBSD.org>
562e8ccc3SEmmanuel Vadot  *
662e8ccc3SEmmanuel Vadot  * Redistribution and use in source and binary forms, with or without
762e8ccc3SEmmanuel Vadot  * modification, are permitted provided that the following conditions
862e8ccc3SEmmanuel Vadot  * are met:
962e8ccc3SEmmanuel Vadot  * 1. Redistributions of source code must retain the above copyright
1062e8ccc3SEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer.
1162e8ccc3SEmmanuel Vadot  * 2. Redistributions in binary form must reproduce the above copyright
1262e8ccc3SEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer in the
1362e8ccc3SEmmanuel Vadot  *    documentation and/or other materials provided with the distribution.
1462e8ccc3SEmmanuel Vadot  *
1562e8ccc3SEmmanuel Vadot  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1662e8ccc3SEmmanuel Vadot  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1762e8ccc3SEmmanuel Vadot  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1862e8ccc3SEmmanuel Vadot  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1962e8ccc3SEmmanuel Vadot  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2062e8ccc3SEmmanuel Vadot  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2162e8ccc3SEmmanuel Vadot  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2262e8ccc3SEmmanuel Vadot  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2362e8ccc3SEmmanuel Vadot  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2462e8ccc3SEmmanuel Vadot  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2562e8ccc3SEmmanuel Vadot  * SUCH DAMAGE.
2662e8ccc3SEmmanuel Vadot  */
2762e8ccc3SEmmanuel Vadot 
2862e8ccc3SEmmanuel Vadot /*
2962e8ccc3SEmmanuel Vadot  * This is a generic syscon driver, whose purpose is to provide access to
3062e8ccc3SEmmanuel Vadot  * various unrelated bits packed in a single register space. It is usually used
3162e8ccc3SEmmanuel Vadot  * as a fallback to more specific driver, but works well enough for simple
3262e8ccc3SEmmanuel Vadot  * access.
3362e8ccc3SEmmanuel Vadot  */
3462e8ccc3SEmmanuel Vadot 
3562e8ccc3SEmmanuel Vadot #include <sys/cdefs.h>
3662e8ccc3SEmmanuel Vadot #include "opt_platform.h"
3762e8ccc3SEmmanuel Vadot 
3862e8ccc3SEmmanuel Vadot #include <sys/param.h>
3962e8ccc3SEmmanuel Vadot #include <sys/systm.h>
4062e8ccc3SEmmanuel Vadot #include <sys/bus.h>
4162e8ccc3SEmmanuel Vadot #include <sys/kernel.h>
4262e8ccc3SEmmanuel Vadot #include <sys/kobj.h>
4362e8ccc3SEmmanuel Vadot #include <sys/lock.h>
4462e8ccc3SEmmanuel Vadot #include <sys/malloc.h>
4562e8ccc3SEmmanuel Vadot #include <sys/module.h>
4662e8ccc3SEmmanuel Vadot #include <sys/rman.h>
4762e8ccc3SEmmanuel Vadot #include <sys/sx.h>
4862e8ccc3SEmmanuel Vadot #include <sys/queue.h>
4962e8ccc3SEmmanuel Vadot 
5062e8ccc3SEmmanuel Vadot #include <machine/bus.h>
5162e8ccc3SEmmanuel Vadot 
5262e8ccc3SEmmanuel Vadot #ifdef FDT
5362e8ccc3SEmmanuel Vadot #include <dev/ofw/ofw_bus.h>
5462e8ccc3SEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h>
5562e8ccc3SEmmanuel Vadot #endif
5662e8ccc3SEmmanuel Vadot 
5762e8ccc3SEmmanuel Vadot #include "syscon_if.h"
5862e8ccc3SEmmanuel Vadot #include "syscon.h"
5962e8ccc3SEmmanuel Vadot 
6062e8ccc3SEmmanuel Vadot /*
6162e8ccc3SEmmanuel Vadot  * Syscon interface details
6262e8ccc3SEmmanuel Vadot  */
6362e8ccc3SEmmanuel Vadot typedef TAILQ_HEAD(syscon_list, syscon) syscon_list_t;
6462e8ccc3SEmmanuel Vadot 
6562e8ccc3SEmmanuel Vadot /*
6662e8ccc3SEmmanuel Vadot  * Declarations
6762e8ccc3SEmmanuel Vadot  */
6862e8ccc3SEmmanuel Vadot static int syscon_method_init(struct syscon *syscon);
6962e8ccc3SEmmanuel Vadot static int syscon_method_uninit(struct syscon *syscon);
7062e8ccc3SEmmanuel Vadot static uint32_t syscon_method_read_4(struct syscon *syscon, bus_size_t offset);
7162e8ccc3SEmmanuel Vadot static int syscon_method_write_4(struct syscon *syscon, bus_size_t offset,
7262e8ccc3SEmmanuel Vadot     uint32_t val);
7362e8ccc3SEmmanuel Vadot static int syscon_method_modify_4(struct syscon *syscon, bus_size_t offset,
7462e8ccc3SEmmanuel Vadot     uint32_t clear_bits, uint32_t set_bits);
7562e8ccc3SEmmanuel Vadot 
7662e8ccc3SEmmanuel Vadot 
7762e8ccc3SEmmanuel Vadot MALLOC_DEFINE(M_SYSCON, "syscon", "Syscon driver");
7862e8ccc3SEmmanuel Vadot 
7962e8ccc3SEmmanuel Vadot static syscon_list_t syscon_list = TAILQ_HEAD_INITIALIZER(syscon_list);
8062e8ccc3SEmmanuel Vadot static struct sx		syscon_topo_lock;
8162e8ccc3SEmmanuel Vadot SX_SYSINIT(syscon_topology, &syscon_topo_lock, "Syscon topology lock");
8262e8ccc3SEmmanuel Vadot 
8362e8ccc3SEmmanuel Vadot /*
8462e8ccc3SEmmanuel Vadot  * Syscon methods.
8562e8ccc3SEmmanuel Vadot  */
8662e8ccc3SEmmanuel Vadot static syscon_method_t syscon_methods[] = {
8762e8ccc3SEmmanuel Vadot 	SYSCONMETHOD(syscon_init,	syscon_method_init),
8862e8ccc3SEmmanuel Vadot 	SYSCONMETHOD(syscon_uninit,	syscon_method_uninit),
8962e8ccc3SEmmanuel Vadot 	SYSCONMETHOD(syscon_read_4,	syscon_method_read_4),
9062e8ccc3SEmmanuel Vadot 	SYSCONMETHOD(syscon_write_4,	syscon_method_write_4),
9162e8ccc3SEmmanuel Vadot 	SYSCONMETHOD(syscon_modify_4,	syscon_method_modify_4),
9262e8ccc3SEmmanuel Vadot 
9362e8ccc3SEmmanuel Vadot 	SYSCONMETHOD_END
9462e8ccc3SEmmanuel Vadot };
9562e8ccc3SEmmanuel Vadot DEFINE_CLASS_0(syscon, syscon_class, syscon_methods, 0);
9662e8ccc3SEmmanuel Vadot 
9762e8ccc3SEmmanuel Vadot #define SYSCON_TOPO_SLOCK()	sx_slock(&syscon_topo_lock)
9862e8ccc3SEmmanuel Vadot #define SYSCON_TOPO_XLOCK()	sx_xlock(&syscon_topo_lock)
9962e8ccc3SEmmanuel Vadot #define SYSCON_TOPO_UNLOCK()	sx_unlock(&syscon_topo_lock)
10062e8ccc3SEmmanuel Vadot #define SYSCON_TOPO_ASSERT()	sx_assert(&syscon_topo_lock, SA_LOCKED)
10162e8ccc3SEmmanuel Vadot #define SYSCON_TOPO_XASSERT()	sx_assert(&syscon_topo_lock, SA_XLOCKED)
10262e8ccc3SEmmanuel Vadot 
10362e8ccc3SEmmanuel Vadot /*
10462e8ccc3SEmmanuel Vadot  * Default syscon methods for base class.
10562e8ccc3SEmmanuel Vadot  */
10662e8ccc3SEmmanuel Vadot static int
syscon_method_init(struct syscon * syscon)10762e8ccc3SEmmanuel Vadot syscon_method_init(struct syscon *syscon)
10862e8ccc3SEmmanuel Vadot {
10962e8ccc3SEmmanuel Vadot 
11062e8ccc3SEmmanuel Vadot 	return (0);
11162e8ccc3SEmmanuel Vadot };
11262e8ccc3SEmmanuel Vadot 
11362e8ccc3SEmmanuel Vadot static int
syscon_method_uninit(struct syscon * syscon)11462e8ccc3SEmmanuel Vadot syscon_method_uninit(struct syscon *syscon)
11562e8ccc3SEmmanuel Vadot {
11662e8ccc3SEmmanuel Vadot 
11762e8ccc3SEmmanuel Vadot 	return (0);
11862e8ccc3SEmmanuel Vadot };
11962e8ccc3SEmmanuel Vadot 
12062e8ccc3SEmmanuel Vadot void *
syscon_get_softc(struct syscon * syscon)12162e8ccc3SEmmanuel Vadot syscon_get_softc(struct syscon *syscon)
12262e8ccc3SEmmanuel Vadot {
12362e8ccc3SEmmanuel Vadot 
12462e8ccc3SEmmanuel Vadot 	return (syscon->softc);
12562e8ccc3SEmmanuel Vadot };
12662e8ccc3SEmmanuel Vadot 
12762e8ccc3SEmmanuel Vadot static uint32_t
syscon_method_read_4(struct syscon * syscon,bus_size_t offset)12862e8ccc3SEmmanuel Vadot syscon_method_read_4(struct syscon *syscon, bus_size_t offset)
12962e8ccc3SEmmanuel Vadot {
13062e8ccc3SEmmanuel Vadot 	uint32_t val;
13162e8ccc3SEmmanuel Vadot 
13262e8ccc3SEmmanuel Vadot 	SYSCON_DEVICE_LOCK(syscon->pdev);
13362e8ccc3SEmmanuel Vadot 	val = SYSCON_UNLOCKED_READ_4(syscon, offset);
13462e8ccc3SEmmanuel Vadot 	SYSCON_DEVICE_UNLOCK(syscon->pdev);
13562e8ccc3SEmmanuel Vadot 	return(val);
13662e8ccc3SEmmanuel Vadot }
13762e8ccc3SEmmanuel Vadot 
13862e8ccc3SEmmanuel Vadot static int
syscon_method_write_4(struct syscon * syscon,bus_size_t offset,uint32_t val)13962e8ccc3SEmmanuel Vadot syscon_method_write_4(struct syscon *syscon, bus_size_t offset, uint32_t val)
14062e8ccc3SEmmanuel Vadot {
14162e8ccc3SEmmanuel Vadot 	int	rv;
14262e8ccc3SEmmanuel Vadot 
14362e8ccc3SEmmanuel Vadot 	SYSCON_DEVICE_LOCK(syscon->pdev);
14462e8ccc3SEmmanuel Vadot 	rv = SYSCON_UNLOCKED_WRITE_4(syscon, offset, val);
14562e8ccc3SEmmanuel Vadot 	SYSCON_DEVICE_UNLOCK(syscon->pdev);
14662e8ccc3SEmmanuel Vadot 	return(rv);
14762e8ccc3SEmmanuel Vadot }
14862e8ccc3SEmmanuel Vadot 
14962e8ccc3SEmmanuel Vadot static int
syscon_method_modify_4(struct syscon * syscon,bus_size_t offset,uint32_t clear_bits,uint32_t set_bits)15062e8ccc3SEmmanuel Vadot syscon_method_modify_4(struct syscon *syscon, bus_size_t offset,
15162e8ccc3SEmmanuel Vadot     uint32_t clear_bits, uint32_t set_bits)
15262e8ccc3SEmmanuel Vadot {
15362e8ccc3SEmmanuel Vadot 	int	rv;
15462e8ccc3SEmmanuel Vadot 
15562e8ccc3SEmmanuel Vadot 	SYSCON_DEVICE_LOCK(syscon->pdev);
15662e8ccc3SEmmanuel Vadot 	rv = SYSCON_UNLOCKED_MODIFY_4(syscon, offset, clear_bits, set_bits);
15762e8ccc3SEmmanuel Vadot 	SYSCON_DEVICE_UNLOCK(syscon->pdev);
15862e8ccc3SEmmanuel Vadot 	return(rv);
15962e8ccc3SEmmanuel Vadot }
16062e8ccc3SEmmanuel Vadot /*
16162e8ccc3SEmmanuel Vadot  * Create and initialize syscon object, but do not register it.
16262e8ccc3SEmmanuel Vadot  */
16362e8ccc3SEmmanuel Vadot struct syscon *
syscon_create(device_t pdev,syscon_class_t syscon_class)16462e8ccc3SEmmanuel Vadot syscon_create(device_t pdev, syscon_class_t syscon_class)
16562e8ccc3SEmmanuel Vadot {
16662e8ccc3SEmmanuel Vadot 	struct syscon *syscon;
16762e8ccc3SEmmanuel Vadot 
16862e8ccc3SEmmanuel Vadot 	/* Create object and initialize it. */
16962e8ccc3SEmmanuel Vadot 	syscon = malloc(sizeof(struct syscon), M_SYSCON,
17062e8ccc3SEmmanuel Vadot 	    M_WAITOK | M_ZERO);
17162e8ccc3SEmmanuel Vadot 	kobj_init((kobj_t)syscon, (kobj_class_t)syscon_class);
17262e8ccc3SEmmanuel Vadot 
17362e8ccc3SEmmanuel Vadot 	/* Allocate softc if required. */
17462e8ccc3SEmmanuel Vadot 	if (syscon_class->size > 0)
17562e8ccc3SEmmanuel Vadot 		syscon->softc = malloc(syscon_class->size, M_SYSCON,
17662e8ccc3SEmmanuel Vadot 		    M_WAITOK | M_ZERO);
17762e8ccc3SEmmanuel Vadot 
17862e8ccc3SEmmanuel Vadot 	/* Rest of init. */
17962e8ccc3SEmmanuel Vadot 	syscon->pdev = pdev;
18062e8ccc3SEmmanuel Vadot 	return (syscon);
18162e8ccc3SEmmanuel Vadot }
18262e8ccc3SEmmanuel Vadot 
18362e8ccc3SEmmanuel Vadot /* Register syscon object. */
18462e8ccc3SEmmanuel Vadot struct syscon *
syscon_register(struct syscon * syscon)18562e8ccc3SEmmanuel Vadot syscon_register(struct syscon *syscon)
18662e8ccc3SEmmanuel Vadot {
18762e8ccc3SEmmanuel Vadot 	int rv;
18862e8ccc3SEmmanuel Vadot 
18962e8ccc3SEmmanuel Vadot #ifdef FDT
19062e8ccc3SEmmanuel Vadot 	if (syscon->ofw_node <= 0)
19162e8ccc3SEmmanuel Vadot 		syscon->ofw_node = ofw_bus_get_node(syscon->pdev);
19262e8ccc3SEmmanuel Vadot 	if (syscon->ofw_node <= 0)
19362e8ccc3SEmmanuel Vadot 		return (NULL);
19462e8ccc3SEmmanuel Vadot #endif
19562e8ccc3SEmmanuel Vadot 
19662e8ccc3SEmmanuel Vadot 	rv = SYSCON_INIT(syscon);
19762e8ccc3SEmmanuel Vadot 	if (rv != 0) {
19862e8ccc3SEmmanuel Vadot 		printf("SYSCON_INIT failed: %d\n", rv);
19962e8ccc3SEmmanuel Vadot 		return (NULL);
20062e8ccc3SEmmanuel Vadot 	}
20162e8ccc3SEmmanuel Vadot 
20262e8ccc3SEmmanuel Vadot #ifdef FDT
20362e8ccc3SEmmanuel Vadot 	OF_device_register_xref(OF_xref_from_node(syscon->ofw_node),
20462e8ccc3SEmmanuel Vadot 	    syscon->pdev);
20562e8ccc3SEmmanuel Vadot #endif
20662e8ccc3SEmmanuel Vadot 	SYSCON_TOPO_XLOCK();
20762e8ccc3SEmmanuel Vadot 	TAILQ_INSERT_TAIL(&syscon_list, syscon, syscon_link);
20862e8ccc3SEmmanuel Vadot 	SYSCON_TOPO_UNLOCK();
20962e8ccc3SEmmanuel Vadot 	return (syscon);
21062e8ccc3SEmmanuel Vadot }
21162e8ccc3SEmmanuel Vadot 
21262e8ccc3SEmmanuel Vadot int
syscon_unregister(struct syscon * syscon)21362e8ccc3SEmmanuel Vadot syscon_unregister(struct syscon *syscon)
21462e8ccc3SEmmanuel Vadot {
21562e8ccc3SEmmanuel Vadot 
21662e8ccc3SEmmanuel Vadot 	SYSCON_TOPO_XLOCK();
21762e8ccc3SEmmanuel Vadot 	TAILQ_REMOVE(&syscon_list, syscon, syscon_link);
21862e8ccc3SEmmanuel Vadot 	SYSCON_TOPO_UNLOCK();
21962e8ccc3SEmmanuel Vadot #ifdef FDT
22062e8ccc3SEmmanuel Vadot 	OF_device_register_xref(OF_xref_from_node(syscon->ofw_node), NULL);
22162e8ccc3SEmmanuel Vadot #endif
22262e8ccc3SEmmanuel Vadot 	return (SYSCON_UNINIT(syscon));
22362e8ccc3SEmmanuel Vadot }
22462e8ccc3SEmmanuel Vadot 
22562e8ccc3SEmmanuel Vadot /**
22662e8ccc3SEmmanuel Vadot  * Provider methods
22762e8ccc3SEmmanuel Vadot  */
22862e8ccc3SEmmanuel Vadot #ifdef FDT
22962e8ccc3SEmmanuel Vadot static struct syscon *
syscon_find_by_ofw_node(phandle_t node)23062e8ccc3SEmmanuel Vadot syscon_find_by_ofw_node(phandle_t node)
23162e8ccc3SEmmanuel Vadot {
23262e8ccc3SEmmanuel Vadot 	struct syscon *entry;
23362e8ccc3SEmmanuel Vadot 
23462e8ccc3SEmmanuel Vadot 	SYSCON_TOPO_ASSERT();
23562e8ccc3SEmmanuel Vadot 
23662e8ccc3SEmmanuel Vadot 	TAILQ_FOREACH(entry, &syscon_list, syscon_link) {
23762e8ccc3SEmmanuel Vadot 		if (entry->ofw_node == node)
23862e8ccc3SEmmanuel Vadot 			return (entry);
23962e8ccc3SEmmanuel Vadot 	}
24062e8ccc3SEmmanuel Vadot 
24162e8ccc3SEmmanuel Vadot 	return (NULL);
24262e8ccc3SEmmanuel Vadot }
24362e8ccc3SEmmanuel Vadot 
24462e8ccc3SEmmanuel Vadot struct syscon *
syscon_create_ofw_node(device_t pdev,syscon_class_t syscon_class,phandle_t node)24562e8ccc3SEmmanuel Vadot syscon_create_ofw_node(device_t pdev, syscon_class_t syscon_class,
24662e8ccc3SEmmanuel Vadot     phandle_t node)
24762e8ccc3SEmmanuel Vadot {
24862e8ccc3SEmmanuel Vadot 	struct syscon *syscon;
24962e8ccc3SEmmanuel Vadot 
25062e8ccc3SEmmanuel Vadot 	syscon = syscon_create(pdev, syscon_class);
25162e8ccc3SEmmanuel Vadot 	if (syscon == NULL)
25262e8ccc3SEmmanuel Vadot 		return (NULL);
25362e8ccc3SEmmanuel Vadot 	syscon->ofw_node = node;
25462e8ccc3SEmmanuel Vadot 	if (syscon_register(syscon) == NULL)
25562e8ccc3SEmmanuel Vadot 		return (NULL);
25662e8ccc3SEmmanuel Vadot 	return (syscon);
25762e8ccc3SEmmanuel Vadot }
25862e8ccc3SEmmanuel Vadot 
25962e8ccc3SEmmanuel Vadot phandle_t
syscon_get_ofw_node(struct syscon * syscon)26062e8ccc3SEmmanuel Vadot syscon_get_ofw_node(struct syscon *syscon)
26162e8ccc3SEmmanuel Vadot {
26262e8ccc3SEmmanuel Vadot 
26362e8ccc3SEmmanuel Vadot 	return (syscon->ofw_node);
26462e8ccc3SEmmanuel Vadot }
26562e8ccc3SEmmanuel Vadot 
26662e8ccc3SEmmanuel Vadot int
syscon_get_by_ofw_node(device_t cdev,phandle_t node,struct syscon ** syscon)26762e8ccc3SEmmanuel Vadot syscon_get_by_ofw_node(device_t cdev, phandle_t node, struct syscon **syscon)
26862e8ccc3SEmmanuel Vadot {
26962e8ccc3SEmmanuel Vadot 
27062e8ccc3SEmmanuel Vadot 	SYSCON_TOPO_SLOCK();
27162e8ccc3SEmmanuel Vadot 	*syscon = syscon_find_by_ofw_node(node);
27262e8ccc3SEmmanuel Vadot 	if (*syscon == NULL) {
27362e8ccc3SEmmanuel Vadot 		SYSCON_TOPO_UNLOCK();
27462e8ccc3SEmmanuel Vadot 		device_printf(cdev, "Failed to find syscon node\n");
27562e8ccc3SEmmanuel Vadot 		return (ENODEV);
27662e8ccc3SEmmanuel Vadot 	}
27762e8ccc3SEmmanuel Vadot 	SYSCON_TOPO_UNLOCK();
27862e8ccc3SEmmanuel Vadot 	return (0);
27962e8ccc3SEmmanuel Vadot }
28062e8ccc3SEmmanuel Vadot 
28162e8ccc3SEmmanuel Vadot int
syscon_get_by_ofw_property(device_t cdev,phandle_t cnode,char * name,struct syscon ** syscon)28262e8ccc3SEmmanuel Vadot syscon_get_by_ofw_property(device_t cdev, phandle_t cnode, char *name,
28362e8ccc3SEmmanuel Vadot     struct syscon **syscon)
28462e8ccc3SEmmanuel Vadot {
28562e8ccc3SEmmanuel Vadot 	pcell_t *cells;
28662e8ccc3SEmmanuel Vadot 	int ncells;
28762e8ccc3SEmmanuel Vadot 
28862e8ccc3SEmmanuel Vadot 	if (cnode <= 0)
28962e8ccc3SEmmanuel Vadot 		cnode = ofw_bus_get_node(cdev);
29062e8ccc3SEmmanuel Vadot 	if (cnode <= 0) {
29162e8ccc3SEmmanuel Vadot 		device_printf(cdev,
29262e8ccc3SEmmanuel Vadot 		    "%s called on not ofw based device\n", __func__);
29362e8ccc3SEmmanuel Vadot 		return (ENXIO);
29462e8ccc3SEmmanuel Vadot 	}
29562e8ccc3SEmmanuel Vadot 	ncells = OF_getencprop_alloc_multi(cnode, name, sizeof(pcell_t),
29662e8ccc3SEmmanuel Vadot 	    (void **)&cells);
29762e8ccc3SEmmanuel Vadot 	if (ncells < 1)
29862e8ccc3SEmmanuel Vadot 		return (ENOENT);
29962e8ccc3SEmmanuel Vadot 
30062e8ccc3SEmmanuel Vadot 	/* Translate to syscon node. */
30162e8ccc3SEmmanuel Vadot 	SYSCON_TOPO_SLOCK();
30262e8ccc3SEmmanuel Vadot 	*syscon = syscon_find_by_ofw_node(OF_node_from_xref(cells[0]));
30362e8ccc3SEmmanuel Vadot 	if (*syscon == NULL) {
30462e8ccc3SEmmanuel Vadot 		SYSCON_TOPO_UNLOCK();
30562e8ccc3SEmmanuel Vadot 		device_printf(cdev, "Failed to find syscon node\n");
30662e8ccc3SEmmanuel Vadot 		OF_prop_free(cells);
30762e8ccc3SEmmanuel Vadot 		return (ENODEV);
30862e8ccc3SEmmanuel Vadot 	}
30962e8ccc3SEmmanuel Vadot 	SYSCON_TOPO_UNLOCK();
31062e8ccc3SEmmanuel Vadot 	OF_prop_free(cells);
31162e8ccc3SEmmanuel Vadot 	return (0);
31262e8ccc3SEmmanuel Vadot }
31362e8ccc3SEmmanuel Vadot #endif
314