diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2016-08-22 18:16:59 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2016-08-22 18:16:59 +0000 |
commit | 83898267684016606f3a3e3bc27877559f6997ea (patch) | |
tree | 69d758b5a64f95afd636507dc5f035966d232134 /sys/dev/ofw | |
parent | a46ac02fa5a491f613ec95ab563381377c82921f (diff) |
Add a reset signal API alongside the clock API.
Diffstat (limited to 'sys/dev/ofw')
-rw-r--r-- | sys/dev/ofw/ofw_clock.c | 135 | ||||
-rw-r--r-- | sys/dev/ofw/ofw_clock.h | 17 |
2 files changed, 150 insertions, 2 deletions
diff --git a/sys/dev/ofw/ofw_clock.c b/sys/dev/ofw/ofw_clock.c index a0ec43a2406..ef86d876bed 100644 --- a/sys/dev/ofw/ofw_clock.c +++ b/sys/dev/ofw/ofw_clock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ofw_clock.c,v 1.2 2016/08/22 11:23:54 kettenis Exp $ */ +/* $OpenBSD: ofw_clock.c,v 1.3 2016/08/22 18:16:58 kettenis Exp $ */ /* * Copyright (c) 2016 Mark Kettenis * @@ -22,6 +22,10 @@ #include <dev/ofw/openfirm.h> #include <dev/ofw/ofw_clock.h> +/* + * Clock functionality. + */ + LIST_HEAD(, clock_device) clock_devices = LIST_HEAD_INITIALIZER(clock_devices); @@ -234,3 +238,132 @@ clock_disable(int node, const char *name) { clock_do_enable(node, name, 0); } + +/* + * Reset functionality. + */ + +LIST_HEAD(, reset_device) reset_devices = + LIST_HEAD_INITIALIZER(reset_devices); + +void +reset_register(struct reset_device *rd) +{ + rd->rd_cells = OF_getpropint(rd->rd_node, "#reset-cells", 0); + rd->rd_phandle = OF_getpropint(rd->rd_node, "phandle", 0); + if (rd->rd_phandle == 0) + return; + + LIST_INSERT_HEAD(&reset_devices, rd, rd_list); +} + +void +reset_assert_cells(uint32_t *cells, int assert) +{ + struct reset_device *rd; + uint32_t phandle = cells[0]; + + LIST_FOREACH(rd, &reset_devices, rd_list) { + if (rd->rd_phandle == phandle) + break; + } + + rd->rd_reset(rd->rd_cookie, &cells[1], assert); +} + +uint32_t * +reset_next_reset(uint32_t *cells) +{ + uint32_t phandle = cells[0]; + int node, ncells; + + node = OF_getnodebyphandle(phandle); + if (node == 0) + return NULL; + + ncells = OF_getpropint(node, "#reset-cells", 0); + return cells + ncells + 1; +} + +int +reset_index(int node, const char *reset) +{ + char *names; + char *name; + char *end; + int idx = 0; + int len; + + if (reset == NULL) + return 0; + + len = OF_getproplen(node, "reset-names"); + if (len <= 0) + return -1; + + names = malloc(len, M_TEMP, M_WAITOK); + OF_getprop(node, "reset-names", names, len); + end = names + len; + name = names; + while (name < end) { + if (strcmp(name, reset) == 0) { + free(names, M_TEMP, len); + return idx; + } + name += strlen(name) + 1; + idx++; + } + free(names, M_TEMP, len); + return -1; +} + +void +reset_do_assert_idx(int node, int idx, int assert) +{ + uint32_t *resets; + uint32_t *reset; + int len; + + len = OF_getproplen(node, "resets"); + if (len <= 0) + return; + + resets = malloc(len, M_TEMP, M_WAITOK); + OF_getpropintarray(node, "resets", resets, len); + + reset = resets; + while (reset && resets < resets + (len / sizeof(uint32_t))) { + if (idx <= 0) + reset_assert_cells(reset, assert); + if (idx == 0) + break; + reset = reset_next_reset(reset); + idx--; + } + + free(resets, M_TEMP, len); +} + +void +reset_do_assert(int node, const char *name, int assert) +{ + int idx; + + idx = reset_index(node, name); + if (idx == -1) + return; + + reset_do_assert_idx(node, idx, assert); +} + +void +reset_assert(int node, const char *name) +{ + reset_do_assert(node, name, 1); +} + +void +reset_deassert(int node, const char *name) +{ + reset_do_assert(node, name, 0); +} diff --git a/sys/dev/ofw/ofw_clock.h b/sys/dev/ofw/ofw_clock.h index d67f959ba41..fdeff05d554 100644 --- a/sys/dev/ofw/ofw_clock.h +++ b/sys/dev/ofw/ofw_clock.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ofw_clock.h,v 1.2 2016/08/22 11:23:54 kettenis Exp $ */ +/* $OpenBSD: ofw_clock.h,v 1.3 2016/08/22 18:16:58 kettenis Exp $ */ /* * Copyright (c) 2016 Mark Kettenis * @@ -50,4 +50,19 @@ clock_disable_all(int node) clock_disable_idx(node, -1); } +struct reset_device { + int rd_node; + void *rd_cookie; + void (*rd_reset)(void *, uint32_t *, int); + + LIST_ENTRY(reset_device) rd_list; + uint32_t rd_phandle; + uint32_t rd_cells; +}; + +void reset_register(struct reset_device *); + +void reset_assert(int, const char *); +void reset_deassert(int, const char *); + #endif /* _DEV_OFW_CLOCK_H_ */ |