diff options
author | Patrick Wildt <patrick@cvs.openbsd.org> | 2018-05-03 10:56:15 +0000 |
---|---|---|
committer | Patrick Wildt <patrick@cvs.openbsd.org> | 2018-05-03 10:56:15 +0000 |
commit | 3a8d988d2a0b27e17873c61c9be749371458f73b (patch) | |
tree | c872b39ba601269188de2ab2118e6657c5e01cb3 /sys | |
parent | 2fe7d8e9ccf38fbb32c2e8da11ac468e1dc69f30 (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.c | 72 | ||||
-rw-r--r-- | sys/dev/ofw/ofw_clock.h | 4 |
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 *); |