2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
5 * Copyright (c) 2017 The FreeBSD Foundation
8 * Portions of this software were developed by Landon Fuller
9 * under sponsorship from the FreeBSD Foundation.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
19 * redistribution must be conditioned upon including a substantially
20 * similar Disclaimer requirement for further binary redistribution.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
26 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
27 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
28 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
31 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33 * THE POSSIBILITY OF SUCH DAMAGES.
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
39 #include <sys/param.h>
40 #include <sys/kernel.h>
43 #include <sys/malloc.h>
44 #include <sys/module.h>
45 #include <sys/mutex.h>
46 #include <sys/sysctl.h>
47 #include <sys/systm.h>
49 #include <machine/bus.h>
50 #include <machine/resource.h>
52 #include <dev/bhnd/bhndreg.h>
53 #include <dev/bhnd/bhndvar.h>
54 #include <dev/bhnd/cores/chipc/chipc.h>
56 #include "bhnd_nvram_map.h"
58 #include "bhnd_pmureg.h"
59 #include "bhnd_pmuvar.h"
61 #include "bhnd_pmu_private.h"
64 * Broadcom PMU driver.
66 * On modern BHND chipsets, the PMU, GCI, and SRENG (Save/Restore Engine?)
67 * register blocks are found within a dedicated PMU core (attached via
68 * the AHB 'always on bus').
70 * On earlier chipsets, these register blocks are found at the same
71 * offsets within the ChipCommon core.
74 devclass_t bhnd_pmu_devclass; /**< bhnd(4) PMU device class */
76 static int bhnd_pmu_sysctl_bus_freq(SYSCTL_HANDLER_ARGS);
77 static int bhnd_pmu_sysctl_cpu_freq(SYSCTL_HANDLER_ARGS);
78 static int bhnd_pmu_sysctl_mem_freq(SYSCTL_HANDLER_ARGS);
80 static uint32_t bhnd_pmu_read_4(bus_size_t reg, void *ctx);
81 static void bhnd_pmu_write_4(bus_size_t reg, uint32_t val, void *ctx);
82 static uint32_t bhnd_pmu_read_chipst(void *ctx);
84 static const struct bhnd_pmu_io bhnd_pmu_res_io = {
85 .rd4 = bhnd_pmu_read_4,
86 .wr4 = bhnd_pmu_write_4,
87 .rd_chipst = bhnd_pmu_read_chipst
91 * Default bhnd_pmu driver implementation of DEVICE_PROBE().
94 bhnd_pmu_probe(device_t dev)
96 return (BUS_PROBE_DEFAULT);
100 * Default bhnd_pmu driver implementation of DEVICE_ATTACH().
102 * @param dev PMU device.
103 * @param res The PMU device registers. The driver will maintain a borrowed
104 * reference to this resource for the lifetime of the device.
107 bhnd_pmu_attach(device_t dev, struct bhnd_resource *res)
109 struct bhnd_pmu_softc *sc;
110 struct sysctl_ctx_list *ctx;
111 struct sysctl_oid *tree;
112 devclass_t bhnd_class;
116 sc = device_get_softc(dev);
120 /* Fetch capability flags */
121 sc->caps = bhnd_bus_read_4(sc->res, BHND_PMU_CAP);
123 /* Find the bus and bus-attached core */
124 bhnd_class = devclass_find("bhnd");
126 while ((bus = device_get_parent(core)) != NULL) {
127 if (device_get_devclass(bus) == bhnd_class)
134 device_printf(sc->dev, "bhnd bus not found\n");
138 /* Fetch chip and board info */
139 sc->cid = *bhnd_get_chipid(core);
140 if ((error = bhnd_read_board_info(core, &sc->board))) {
141 device_printf(sc->dev, "error fetching board info: %d\n",
146 /* Initialize query state */
147 error = bhnd_pmu_query_init(&sc->query, dev, sc->cid, &bhnd_pmu_res_io,
151 sc->io = sc->query.io;
152 sc->io_ctx = sc->query.io_ctx;
156 /* Allocate our own core clkctl state directly; we use this to wait on
157 * PMU state transitions, avoiding a cyclic dependency between bhnd(4)'s
158 * clkctl handling and registration of this device as a PMU */
159 sc->clkctl = bhnd_alloc_core_clkctl(core, dev, sc->res, BHND_CLK_CTL_ST,
160 BHND_PMU_MAX_TRANSITION_DLY);
161 if (sc->clkctl == NULL) {
162 device_printf(sc->dev, "failed to allocate clkctl for %s\n",
163 device_get_nameunit(core));
168 /* Locate ChipCommon device */
169 sc->chipc_dev = bhnd_retain_provider(dev, BHND_SERVICE_CHIPC);
170 if (sc->chipc_dev == NULL) {
171 device_printf(sc->dev, "chipcommon device not found\n");
177 if ((error = bhnd_pmu_init(sc))) {
178 device_printf(sc->dev, "PMU init failed: %d\n", error);
182 /* Register ourselves with the bus */
183 if ((error = bhnd_register_provider(dev, BHND_SERVICE_PMU))) {
184 device_printf(sc->dev, "failed to register PMU with bus : %d\n",
189 /* Set up sysctl nodes */
190 ctx = device_get_sysctl_ctx(dev);
191 tree = device_get_sysctl_tree(dev);
193 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
194 "bus_freq", CTLTYPE_UINT | CTLFLAG_RD, sc, 0,
195 bhnd_pmu_sysctl_bus_freq, "IU", "Bus clock frequency");
197 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
198 "cpu_freq", CTLTYPE_UINT | CTLFLAG_RD, sc, 0,
199 bhnd_pmu_sysctl_cpu_freq, "IU", "CPU clock frequency");
201 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
202 "mem_freq", CTLTYPE_UINT | CTLFLAG_RD, sc, 0,
203 bhnd_pmu_sysctl_mem_freq, "IU", "Memory clock frequency");
208 BPMU_LOCK_DESTROY(sc);
209 bhnd_pmu_query_fini(&sc->query);
211 if (sc->clkctl != NULL)
212 bhnd_free_core_clkctl(sc->clkctl);
214 if (sc->chipc_dev != NULL) {
215 bhnd_release_provider(sc->dev, sc->chipc_dev,
223 * Default bhnd_pmu driver implementation of DEVICE_DETACH().
226 bhnd_pmu_detach(device_t dev)
228 struct bhnd_pmu_softc *sc;
231 sc = device_get_softc(dev);
233 if ((error = bhnd_deregister_provider(dev, BHND_SERVICE_ANY)))
236 BPMU_LOCK_DESTROY(sc);
237 bhnd_pmu_query_fini(&sc->query);
238 bhnd_free_core_clkctl(sc->clkctl);
239 bhnd_release_provider(sc->dev, sc->chipc_dev, BHND_SERVICE_CHIPC);
245 * Default bhnd_pmu driver implementation of DEVICE_SUSPEND().
248 bhnd_pmu_suspend(device_t dev)
254 * Default bhnd_pmu driver implementation of DEVICE_RESUME().
257 bhnd_pmu_resume(device_t dev)
259 struct bhnd_pmu_softc *sc;
262 sc = device_get_softc(dev);
264 /* Re-initialize PMU */
265 if ((error = bhnd_pmu_init(sc))) {
266 device_printf(sc->dev, "PMU init failed: %d\n", error);
274 bhnd_pmu_sysctl_bus_freq(SYSCTL_HANDLER_ARGS)
276 struct bhnd_pmu_softc *sc;
282 freq = bhnd_pmu_si_clock(&sc->query);
285 return (sysctl_handle_32(oidp, NULL, freq, req));
289 bhnd_pmu_sysctl_cpu_freq(SYSCTL_HANDLER_ARGS)
291 struct bhnd_pmu_softc *sc;
297 freq = bhnd_pmu_cpu_clock(&sc->query);
300 return (sysctl_handle_32(oidp, NULL, freq, req));
304 bhnd_pmu_sysctl_mem_freq(SYSCTL_HANDLER_ARGS)
306 struct bhnd_pmu_softc *sc;
312 freq = bhnd_pmu_mem_clock(&sc->query);
315 return (sysctl_handle_32(oidp, NULL, freq, req));
319 * Default bhnd_pmu driver implementation of BHND_PMU_READ_CHIPCTRL().
322 bhnd_pmu_read_chipctrl_method(device_t dev, uint32_t reg)
324 struct bhnd_pmu_softc *sc;
327 sc = device_get_softc(dev);
330 rval = BHND_PMU_CCTRL_READ(sc, reg);
337 * Default bhnd_pmu driver implementation of BHND_PMU_WRITE_CHIPCTRL().
340 bhnd_pmu_write_chipctrl_method(device_t dev, uint32_t reg, uint32_t value,
343 struct bhnd_pmu_softc *sc = device_get_softc(dev);
346 BHND_PMU_CCTRL_WRITE(sc, reg, value, mask);
351 * Default bhnd_pmu driver implementation of BHND_PMU_READ_REGCTRL().
354 bhnd_pmu_read_regctrl_method(device_t dev, uint32_t reg)
356 struct bhnd_pmu_softc *sc;
359 sc = device_get_softc(dev);
362 rval = BHND_PMU_REGCTRL_READ(sc, reg);
369 * Default bhnd_pmu driver implementation of BHND_PMU_WRITE_REGCTRL().
372 bhnd_pmu_write_regctrl_method(device_t dev, uint32_t reg, uint32_t value,
375 struct bhnd_pmu_softc *sc = device_get_softc(dev);
378 BHND_PMU_REGCTRL_WRITE(sc, reg, value, mask);
383 * Default bhnd_pmu driver implementation of BHND_PMU_READ_PLLCTRL().
386 bhnd_pmu_read_pllctrl_method(device_t dev, uint32_t reg)
388 struct bhnd_pmu_softc *sc;
391 sc = device_get_softc(dev);
394 rval = BHND_PMU_PLL_READ(sc, reg);
401 * Default bhnd_pmu driver implementation of BHND_PMU_WRITE_PLLCTRL().
404 bhnd_pmu_write_pllctrl_method(device_t dev, uint32_t reg, uint32_t value,
407 struct bhnd_pmu_softc *sc = device_get_softc(dev);
410 BHND_PMU_PLL_WRITE(sc, reg, value, mask);
415 * Default bhnd_pmu driver implementation of BHND_PMU_SET_VOLTAGE_RAW().
418 bhnd_pmu_set_voltage_raw_method(device_t dev, bhnd_pmu_regulator regulator,
421 struct bhnd_pmu_softc *sc;
424 sc = device_get_softc(dev);
427 case BHND_REGULATOR_PAREF_LDO:
428 if (value > UINT8_MAX)
432 error = bhnd_pmu_set_ldo_voltage(sc, SET_LDO_VOLTAGE_PAREF,
444 * Default bhnd_pmu driver implementation of BHND_PMU_ENABLE_REGULATOR().
447 bhnd_pmu_enable_regulator_method(device_t dev, bhnd_pmu_regulator regulator)
449 struct bhnd_pmu_softc *sc;
452 sc = device_get_softc(dev);
455 case BHND_REGULATOR_PAREF_LDO:
457 error = bhnd_pmu_paref_ldo_enable(sc, true);
468 * Default bhnd_pmu driver implementation of BHND_PMU_DISABLE_REGULATOR().
471 bhnd_pmu_disable_regulator_method(device_t dev, bhnd_pmu_regulator regulator)
473 struct bhnd_pmu_softc *sc;
476 sc = device_get_softc(dev);
479 case BHND_REGULATOR_PAREF_LDO:
481 error = bhnd_pmu_paref_ldo_enable(sc, false);
493 * Default bhnd_pmu driver implementation of BHND_PMU_GET_CLOCK_LATENCY().
496 bhnd_pmu_get_clock_latency_method(device_t dev, bhnd_clock clock,
499 struct bhnd_pmu_softc *sc;
503 sc = device_get_softc(dev);
508 error = bhnd_pmu_fast_pwrup_delay(sc, &pwrup_delay);
514 *latency = pwrup_delay;
523 * Default bhnd_pmu driver implementation of BHND_PMU_GET_CLOCK_FREQ().
526 bhnd_pmu_get_clock_freq_method(device_t dev, bhnd_clock clock, uint32_t *freq)
528 struct bhnd_pmu_softc *sc = device_get_softc(dev);
533 *freq = bhnd_pmu_si_clock(&sc->query);
537 *freq = bhnd_pmu_alp_clock(&sc->query);
541 *freq = bhnd_pmu_ilp_clock(&sc->query);
555 * Default bhnd_pmu driver implementation of BHND_PMU_REQUEST_SPURAVOID().
558 bhnd_pmu_request_spuravoid_method(device_t dev, bhnd_pmu_spuravoid spuravoid)
560 struct bhnd_pmu_softc *sc;
563 sc = device_get_softc(dev);
566 error = bhnd_pmu_set_spuravoid(sc, spuravoid);
573 * Default bhnd_pmu driver implementation of BHND_PMU_GET_TRANSITION_LATENCY().
576 bhnd_pmu_get_max_transition_latency_method(device_t dev)
578 return (BHND_PMU_MAX_TRANSITION_DLY);
581 /* bhnd_pmu_query read_4 callback */
583 bhnd_pmu_read_4(bus_size_t reg, void *ctx)
585 struct bhnd_pmu_softc *sc = ctx;
586 return (bhnd_bus_read_4(sc->res, reg));
589 /* bhnd_pmu_query write_4 callback */
591 bhnd_pmu_write_4(bus_size_t reg, uint32_t val, void *ctx)
593 struct bhnd_pmu_softc *sc = ctx;
594 return (bhnd_bus_write_4(sc->res, reg, val));
597 /* bhnd_pmu_query read_chipst callback */
599 bhnd_pmu_read_chipst(void *ctx)
601 struct bhnd_pmu_softc *sc = ctx;
602 return (BHND_CHIPC_READ_CHIPST(sc->chipc_dev));
605 static device_method_t bhnd_pmu_methods[] = {
606 /* Device interface */
607 DEVMETHOD(device_probe, bhnd_pmu_probe),
608 DEVMETHOD(device_detach, bhnd_pmu_detach),
609 DEVMETHOD(device_suspend, bhnd_pmu_suspend),
610 DEVMETHOD(device_resume, bhnd_pmu_resume),
612 /* BHND PMU interface */
613 DEVMETHOD(bhnd_pmu_read_chipctrl, bhnd_pmu_read_chipctrl_method),
614 DEVMETHOD(bhnd_pmu_write_chipctrl, bhnd_pmu_write_chipctrl_method),
615 DEVMETHOD(bhnd_pmu_read_regctrl, bhnd_pmu_read_regctrl_method),
616 DEVMETHOD(bhnd_pmu_write_regctrl, bhnd_pmu_write_regctrl_method),
617 DEVMETHOD(bhnd_pmu_read_pllctrl, bhnd_pmu_read_pllctrl_method),
618 DEVMETHOD(bhnd_pmu_write_pllctrl, bhnd_pmu_write_pllctrl_method),
619 DEVMETHOD(bhnd_pmu_set_voltage_raw, bhnd_pmu_set_voltage_raw_method),
620 DEVMETHOD(bhnd_pmu_enable_regulator, bhnd_pmu_enable_regulator_method),
621 DEVMETHOD(bhnd_pmu_disable_regulator, bhnd_pmu_disable_regulator_method),
623 DEVMETHOD(bhnd_pmu_get_clock_latency, bhnd_pmu_get_clock_latency_method),
624 DEVMETHOD(bhnd_pmu_get_clock_freq, bhnd_pmu_get_clock_freq_method),
626 DEVMETHOD(bhnd_pmu_get_max_transition_latency, bhnd_pmu_get_max_transition_latency_method),
627 DEVMETHOD(bhnd_pmu_request_spuravoid, bhnd_pmu_request_spuravoid_method),
632 DEFINE_CLASS_0(bhnd_pmu, bhnd_pmu_driver, bhnd_pmu_methods, sizeof(struct bhnd_pmu_softc));
633 MODULE_VERSION(bhnd_pmu, 1);