summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2018-05-03 10:56:15 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2018-05-03 10:56:15 +0000
commit3a8d988d2a0b27e17873c61c9be749371458f73b (patch)
treec872b39ba601269188de2ab2118e6657c5e01cb3 /sys
parent2fe7d8e9ccf38fbb32c2e8da11ac468e1dc69f30 (diff)
Add an API to configure clocks to specific pre-assigned values. These
values are defined in the device tree and make sure that all clocks needed for controller and driver operation are configured as expected. This allows modifying a clock's rate and parent. For now expect that a parent clock is on the same controller as the muxed one. ok kettenis@
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ofw/ofw_clock.c72
-rw-r--r--sys/dev/ofw/ofw_clock.h4
2 files changed, 74 insertions, 2 deletions
diff --git a/sys/dev/ofw/ofw_clock.c b/sys/dev/ofw/ofw_clock.c
index 1ea57677a6e..459a24f3838 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.8 2017/03/12 11:44:42 kettenis Exp $ */
+/* $OpenBSD: ofw_clock.c,v 1.9 2018/05/03 10:56:14 patrick Exp $ */
/*
* Copyright (c) 2016 Mark Kettenis
*
@@ -91,6 +91,27 @@ clock_set_frequency_cells(uint32_t *cells, uint32_t freq)
return -1;
}
+int
+clock_set_parent_cells(uint32_t *cells, uint32_t *pcells)
+{
+ struct clock_device *cd;
+ uint32_t phandle = cells[0];
+
+ /* We expect that clocks are on the same handle. */
+ if (phandle != pcells[0])
+ return -1;
+
+ LIST_FOREACH(cd, &clock_devices, cd_list) {
+ if (cd->cd_phandle == phandle)
+ break;
+ }
+
+ if (cd && cd->cd_set_parent)
+ return cd->cd_set_parent(cd->cd_cookie, &cells[1], &pcells[1]);
+
+ return -1;
+}
+
void
clock_enable_cells(uint32_t *cells, int on)
{
@@ -265,6 +286,55 @@ clock_disable(int node, const char *name)
clock_do_enable(node, name, 0);
}
+void
+clock_set_assigned(int node)
+{
+ uint32_t *clocks, *parents, *rates;
+ uint32_t *clock, *parent, *rate;
+ int clen, plen, rlen;
+
+ clen = OF_getproplen(node, "assigned-clocks");
+ plen = OF_getproplen(node, "assigned-clock-parents");
+ rlen = OF_getproplen(node, "assigned-clock-rates");
+
+ if (clen <= 0 || (plen <= 0 && rlen <= 0))
+ return;
+
+ clock = clocks = malloc(clen, M_TEMP, M_WAITOK);
+ OF_getpropintarray(node, "assigned-clocks", clocks, clen);
+
+ parent = parents = NULL;
+ if (plen > 0) {
+ parent = parents = malloc(plen, M_TEMP, M_WAITOK);
+ OF_getpropintarray(node, "assigned-clock-parents", parents, plen);
+ }
+ rate = rates = NULL;
+ if (rlen > 0) {
+ rate = rates = malloc(rlen, M_TEMP, M_WAITOK);
+ OF_getpropintarray(node, "assigned-clock-rates", rates, rlen);
+ }
+
+ while (clock && clock < clocks + (clen / sizeof(uint32_t))) {
+ if (parent && parent < parent + (plen / sizeof(uint32_t)))
+ if (*parent != 0)
+ clock_set_parent_cells(clock, parent);
+
+ if (rate && rate < rates + (rlen / sizeof(uint32_t)))
+ if (*rate != 0)
+ clock_set_frequency_cells(clock, *rate);
+
+ clock = clock_next_clock(clock);
+ if (parent)
+ parent = clock_next_clock(parent);
+ if (rate)
+ rate++;
+ }
+
+ free(clocks, M_TEMP, clen);
+ free(parents, M_TEMP, plen);
+ free(rates, M_TEMP, rlen);
+}
+
/*
* Reset functionality.
*/
diff --git a/sys/dev/ofw/ofw_clock.h b/sys/dev/ofw/ofw_clock.h
index 10848422096..34dd92a9e31 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.5 2016/08/23 21:30:18 kettenis Exp $ */
+/* $OpenBSD: ofw_clock.h,v 1.6 2018/05/03 10:56:14 patrick Exp $ */
/*
* Copyright (c) 2016 Mark Kettenis
*
@@ -23,6 +23,7 @@ struct clock_device {
void *cd_cookie;
uint32_t (*cd_get_frequency)(void *, uint32_t *);
int (*cd_set_frequency)(void *, uint32_t *, uint32_t);
+ int (*cd_set_parent)(void *, uint32_t *, uint32_t *);
void (*cd_enable)(void *, uint32_t *, int);
LIST_ENTRY(clock_device) cd_list;
@@ -35,6 +36,7 @@ void clock_register(struct clock_device *);
uint32_t clock_get_frequency(int, const char *);
uint32_t clock_get_frequency_idx(int, int);
int clock_set_frequency(int, const char *, uint32_t);
+void clock_set_assigned(int);
void clock_enable(int, const char *);
void clock_enable_idx(int, int);
void clock_disable(int, const char *);