1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
5 * Copyright (c) 2017 The FreeBSD Foundation
6 * All rights reserved.
7 *
8 * Portions of this software were developed by Landon Fuller
9 * under sponsorship from the FreeBSD Foundation.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
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.
21 *
22 * NO WARRANTY
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.
34 */
35
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38
39 #include <sys/param.h>
40 #include <sys/kernel.h>
41 #include <sys/lock.h>
42 #include <sys/bus.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>
48
49 #include <machine/bus.h>
50 #include <machine/resource.h>
51
52 #include <dev/bhnd/bhndreg.h>
53 #include <dev/bhnd/bhndvar.h>
54 #include <dev/bhnd/cores/chipc/chipc.h>
55
56 #include "bhnd_nvram_map.h"
57
58 #include "bhnd_pmureg.h"
59 #include "bhnd_pmuvar.h"
60
61 #include "bhnd_pmu_private.h"
62
63 /*
64 * Broadcom PMU driver.
65 *
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').
69 *
70 * On earlier chipsets, these register blocks are found at the same
71 * offsets within the ChipCommon core.
72 */
73
74 static int bhnd_pmu_sysctl_bus_freq(SYSCTL_HANDLER_ARGS);
75 static int bhnd_pmu_sysctl_cpu_freq(SYSCTL_HANDLER_ARGS);
76 static int bhnd_pmu_sysctl_mem_freq(SYSCTL_HANDLER_ARGS);
77
78 static uint32_t bhnd_pmu_read_4(bus_size_t reg, void *ctx);
79 static void bhnd_pmu_write_4(bus_size_t reg, uint32_t val, void *ctx);
80 static uint32_t bhnd_pmu_read_chipst(void *ctx);
81
82 static const struct bhnd_pmu_io bhnd_pmu_res_io = {
83 .rd4 = bhnd_pmu_read_4,
84 .wr4 = bhnd_pmu_write_4,
85 .rd_chipst = bhnd_pmu_read_chipst
86 };
87
88 /**
89 * Default bhnd_pmu driver implementation of DEVICE_PROBE().
90 */
91 int
92 bhnd_pmu_probe(device_t dev)
93 {
94 return (BUS_PROBE_DEFAULT);
95 }
96
97 /**
98 * Default bhnd_pmu driver implementation of DEVICE_ATTACH().
99 *
100 * @param dev PMU device.
101 * @param res The PMU device registers. The driver will maintain a borrowed
102 * reference to this resource for the lifetime of the device.
103 */
104 int
105 bhnd_pmu_attach(device_t dev, struct bhnd_resource *res)
106 {
107 struct bhnd_pmu_softc *sc;
108 struct sysctl_ctx_list *ctx;
109 struct sysctl_oid *tree;
110 devclass_t bhnd_class;
111 device_t core, bus;
112 int error;
113
114 sc = device_get_softc(dev);
115 sc->dev = dev;
116 sc->res = res;
117
118 /* Fetch capability flags */
119 sc->caps = bhnd_bus_read_4(sc->res, BHND_PMU_CAP);
120
121 /* Find the bus and bus-attached core */
122 bhnd_class = devclass_find("bhnd");
123 core = sc->dev;
124 while ((bus = device_get_parent(core)) != NULL) {
125 if (device_get_devclass(bus) == bhnd_class)
126 break;
127
128 core = bus;
129 }
130
131 if (core == NULL) {
132 device_printf(sc->dev, "bhnd bus not found\n");
133 return (ENXIO);
134 }
135
136 /* Fetch chip and board info */
137 sc->cid = *bhnd_get_chipid(core);
138 if ((error = bhnd_read_board_info(core, &sc->board))) {
139 device_printf(sc->dev, "error fetching board info: %d\n",
140 error);
141 return (ENXIO);
142 }
143
144 /* Initialize query state */
145 error = bhnd_pmu_query_init(&sc->query, dev, sc->cid, &bhnd_pmu_res_io,
146 sc);
147 if (error)
148 return (error);
149 sc->io = sc->query.io;
150 sc->io_ctx = sc->query.io_ctx;
151
152 BPMU_LOCK_INIT(sc);
153
154 /* Allocate our own core clkctl state directly; we use this to wait on
155 * PMU state transitions, avoiding a cyclic dependency between bhnd(4)'s
156 * clkctl handling and registration of this device as a PMU */
157 sc->clkctl = bhnd_alloc_core_clkctl(core, dev, sc->res, BHND_CLK_CTL_ST,
158 BHND_PMU_MAX_TRANSITION_DLY);
159 if (sc->clkctl == NULL) {
160 device_printf(sc->dev, "failed to allocate clkctl for %s\n",
161 device_get_nameunit(core));
162 error = ENOMEM;
163 goto failed;
164 }
165
166 /* Locate ChipCommon device */
167 sc->chipc_dev = bhnd_retain_provider(dev, BHND_SERVICE_CHIPC);
168 if (sc->chipc_dev == NULL) {
169 device_printf(sc->dev, "chipcommon device not found\n");
170 error = ENXIO;
171 goto failed;
172 }
173
174 /* Initialize PMU */
175 if ((error = bhnd_pmu_init(sc))) {
176 device_printf(sc->dev, "PMU init failed: %d\n", error);
177 goto failed;
178 }
179
180 /* Register ourselves with the bus */
181 if ((error = bhnd_register_provider(dev, BHND_SERVICE_PMU))) {
182 device_printf(sc->dev, "failed to register PMU with bus : %d\n",
183 error);
184 goto failed;
185 }
186
187 /* Set up sysctl nodes */
188 ctx = device_get_sysctl_ctx(dev);
189 tree = device_get_sysctl_tree(dev);
190
191 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
192 "bus_freq", CTLTYPE_UINT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, sc, 0,
193 bhnd_pmu_sysctl_bus_freq, "IU", "Bus clock frequency");
194
195 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
196 "cpu_freq", CTLTYPE_UINT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, sc, 0,
197 bhnd_pmu_sysctl_cpu_freq, "IU", "CPU clock frequency");
198
199 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
200 "mem_freq", CTLTYPE_UINT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, sc, 0,
201 bhnd_pmu_sysctl_mem_freq, "IU", "Memory clock frequency");
202
203 return (0);
204
205 failed:
206 BPMU_LOCK_DESTROY(sc);
207 bhnd_pmu_query_fini(&sc->query);
208
209 if (sc->clkctl != NULL)
210 bhnd_free_core_clkctl(sc->clkctl);
211
212 if (sc->chipc_dev != NULL) {
213 bhnd_release_provider(sc->dev, sc->chipc_dev,
214 BHND_SERVICE_CHIPC);
215 }
216
217 return (error);
218 }
219
220 /**
221 * Default bhnd_pmu driver implementation of DEVICE_DETACH().
222 */
223 int
224 bhnd_pmu_detach(device_t dev)
225 {
226 struct bhnd_pmu_softc *sc;
227 int error;
228
229 sc = device_get_softc(dev);
230
231 if ((error = bhnd_deregister_provider(dev, BHND_SERVICE_ANY)))
232 return (error);
233
234 BPMU_LOCK_DESTROY(sc);
235 bhnd_pmu_query_fini(&sc->query);
236 bhnd_free_core_clkctl(sc->clkctl);
237 bhnd_release_provider(sc->dev, sc->chipc_dev, BHND_SERVICE_CHIPC);
238
239 return (0);
240 }
241
242 /**
243 * Default bhnd_pmu driver implementation of DEVICE_SUSPEND().
244 */
245 int
246 bhnd_pmu_suspend(device_t dev)
247 {
248 return (0);
249 }
250
251 /**
252 * Default bhnd_pmu driver implementation of DEVICE_RESUME().
253 */
254 int
255 bhnd_pmu_resume(device_t dev)
256 {
257 struct bhnd_pmu_softc *sc;
258 int error;
259
260 sc = device_get_softc(dev);
261
262 /* Re-initialize PMU */
263 if ((error = bhnd_pmu_init(sc))) {
264 device_printf(sc->dev, "PMU init failed: %d\n", error);
265 return (error);
266 }
267
268 return (0);
269 }
270
271 static int
272 bhnd_pmu_sysctl_bus_freq(SYSCTL_HANDLER_ARGS)
273 {
274 struct bhnd_pmu_softc *sc;
275 uint32_t freq;
276
277 sc = arg1;
278
279 BPMU_LOCK(sc);
280 freq = bhnd_pmu_si_clock(&sc->query);
281 BPMU_UNLOCK(sc);
282
283 return (sysctl_handle_32(oidp, NULL, freq, req));
284 }
285
286 static int
287 bhnd_pmu_sysctl_cpu_freq(SYSCTL_HANDLER_ARGS)
288 {
289 struct bhnd_pmu_softc *sc;
290 uint32_t freq;
291
292 sc = arg1;
293
294 BPMU_LOCK(sc);
295 freq = bhnd_pmu_cpu_clock(&sc->query);
296 BPMU_UNLOCK(sc);
297
298 return (sysctl_handle_32(oidp, NULL, freq, req));
299 }
300
301 static int
302 bhnd_pmu_sysctl_mem_freq(SYSCTL_HANDLER_ARGS)
303 {
304 struct bhnd_pmu_softc *sc;
305 uint32_t freq;
306
307 sc = arg1;
308
309 BPMU_LOCK(sc);
310 freq = bhnd_pmu_mem_clock(&sc->query);
311 BPMU_UNLOCK(sc);
312
313 return (sysctl_handle_32(oidp, NULL, freq, req));
314 }
315
316 /**
317 * Default bhnd_pmu driver implementation of BHND_PMU_READ_CHIPCTRL().
318 */
319 static uint32_t
320 bhnd_pmu_read_chipctrl_method(device_t dev, uint32_t reg)
321 {
322 struct bhnd_pmu_softc *sc;
323 uint32_t rval;
324
325 sc = device_get_softc(dev);
326
327 BPMU_LOCK(sc);
328 rval = BHND_PMU_CCTRL_READ(sc, reg);
329 BPMU_UNLOCK(sc);
330
331 return (rval);
332 }
333
334 /**
335 * Default bhnd_pmu driver implementation of BHND_PMU_WRITE_CHIPCTRL().
336 */
337 static void
338 bhnd_pmu_write_chipctrl_method(device_t dev, uint32_t reg, uint32_t value,
339 uint32_t mask)
340 {
341 struct bhnd_pmu_softc *sc = device_get_softc(dev);
342
343 BPMU_LOCK(sc);
344 BHND_PMU_CCTRL_WRITE(sc, reg, value, mask);
345 BPMU_UNLOCK(sc);
346 }
347
348 /**
349 * Default bhnd_pmu driver implementation of BHND_PMU_READ_REGCTRL().
350 */
351 static uint32_t
352 bhnd_pmu_read_regctrl_method(device_t dev, uint32_t reg)
353 {
354 struct bhnd_pmu_softc *sc;
355 uint32_t rval;
356
357 sc = device_get_softc(dev);
358
359 BPMU_LOCK(sc);
360 rval = BHND_PMU_REGCTRL_READ(sc, reg);
361 BPMU_UNLOCK(sc);
362
363 return (rval);
364 }
365
366 /**
367 * Default bhnd_pmu driver implementation of BHND_PMU_WRITE_REGCTRL().
368 */
369 static void
370 bhnd_pmu_write_regctrl_method(device_t dev, uint32_t reg, uint32_t value,
371 uint32_t mask)
372 {
373 struct bhnd_pmu_softc *sc = device_get_softc(dev);
374
375 BPMU_LOCK(sc);
376 BHND_PMU_REGCTRL_WRITE(sc, reg, value, mask);
377 BPMU_UNLOCK(sc);
378 }
379
380 /**
381 * Default bhnd_pmu driver implementation of BHND_PMU_READ_PLLCTRL().
382 */
383 static uint32_t
384 bhnd_pmu_read_pllctrl_method(device_t dev, uint32_t reg)
385 {
386 struct bhnd_pmu_softc *sc;
387 uint32_t rval;
388
389 sc = device_get_softc(dev);
390
391 BPMU_LOCK(sc);
392 rval = BHND_PMU_PLL_READ(sc, reg);
393 BPMU_UNLOCK(sc);
394
395 return (rval);
396 }
397
398 /**
399 * Default bhnd_pmu driver implementation of BHND_PMU_WRITE_PLLCTRL().
400 */
401 static void
402 bhnd_pmu_write_pllctrl_method(device_t dev, uint32_t reg, uint32_t value,
403 uint32_t mask)
404 {
405 struct bhnd_pmu_softc *sc = device_get_softc(dev);
406
407 BPMU_LOCK(sc);
408 BHND_PMU_PLL_WRITE(sc, reg, value, mask);
409 BPMU_UNLOCK(sc);
410 }
411
412 /**
413 * Default bhnd_pmu driver implementation of BHND_PMU_SET_VOLTAGE_RAW().
414 */
415 static int
416 bhnd_pmu_set_voltage_raw_method(device_t dev, bhnd_pmu_regulator regulator,
417 uint32_t value)
418 {
419 struct bhnd_pmu_softc *sc;
420 int error;
421
422 sc = device_get_softc(dev);
423
424 switch (regulator) {
425 case BHND_REGULATOR_PAREF_LDO:
426 if (value > UINT8_MAX)
427 return (EINVAL);
428
429 BPMU_LOCK(sc);
430 error = bhnd_pmu_set_ldo_voltage(sc, SET_LDO_VOLTAGE_PAREF,
431 value);
432 BPMU_UNLOCK(sc);
433
434 return (error);
435
436 default:
437 return (ENODEV);
438 }
439 }
440
441 /**
442 * Default bhnd_pmu driver implementation of BHND_PMU_ENABLE_REGULATOR().
443 */
444 static int
445 bhnd_pmu_enable_regulator_method(device_t dev, bhnd_pmu_regulator regulator)
446 {
447 struct bhnd_pmu_softc *sc;
448 int error;
449
450 sc = device_get_softc(dev);
451
452 switch (regulator) {
453 case BHND_REGULATOR_PAREF_LDO:
454 BPMU_LOCK(sc);
455 error = bhnd_pmu_paref_ldo_enable(sc, true);
456 BPMU_UNLOCK(sc);
457
458 return (error);
459
460 default:
461 return (ENODEV);
462 }
463 }
464
465 /**
466 * Default bhnd_pmu driver implementation of BHND_PMU_DISABLE_REGULATOR().
467 */
468 static int
469 bhnd_pmu_disable_regulator_method(device_t dev, bhnd_pmu_regulator regulator)
470 {
471 struct bhnd_pmu_softc *sc;
472 int error;
473
474 sc = device_get_softc(dev);
475
476 switch (regulator) {
477 case BHND_REGULATOR_PAREF_LDO:
478 BPMU_LOCK(sc);
479 error = bhnd_pmu_paref_ldo_enable(sc, false);
480 BPMU_UNLOCK(sc);
481
482 return (error);
483
484 default:
485 return (ENODEV);
486 }
487 }
488
489 /**
490 * Default bhnd_pmu driver implementation of BHND_PMU_GET_CLOCK_LATENCY().
491 */
492 static int
493 bhnd_pmu_get_clock_latency_method(device_t dev, bhnd_clock clock,
494 u_int *latency)
495 {
496 struct bhnd_pmu_softc *sc;
497 u_int pwrup_delay;
498 int error;
499
500 sc = device_get_softc(dev);
501
502 switch (clock) {
503 case BHND_CLOCK_HT:
504 BPMU_LOCK(sc);
505 error = bhnd_pmu_fast_pwrup_delay(sc, &pwrup_delay);
506 BPMU_UNLOCK(sc);
507
508 if (error)
509 return (error);
510
511 *latency = pwrup_delay;
512 return (0);
513
514 default:
515 return (ENODEV);
516 }
517 }
518
519 /**
520 * Default bhnd_pmu driver implementation of BHND_PMU_GET_CLOCK_FREQ().
521 */
522 static int
523 bhnd_pmu_get_clock_freq_method(device_t dev, bhnd_clock clock, uint32_t *freq)
524 {
525 struct bhnd_pmu_softc *sc = device_get_softc(dev);
526
527 BPMU_LOCK(sc);
528 switch (clock) {
529 case BHND_CLOCK_HT:
530 *freq = bhnd_pmu_si_clock(&sc->query);
531 break;
532
533 case BHND_CLOCK_ALP:
534 *freq = bhnd_pmu_alp_clock(&sc->query);
535 break;
536
537 case BHND_CLOCK_ILP:
538 *freq = bhnd_pmu_ilp_clock(&sc->query);
539 break;
540
541 case BHND_CLOCK_DYN:
542 default:
543 BPMU_UNLOCK(sc);
544 return (ENODEV);
545 }
546
547 BPMU_UNLOCK(sc);
548 return (0);
549 }
550
551 /**
552 * Default bhnd_pmu driver implementation of BHND_PMU_REQUEST_SPURAVOID().
553 */
554 static int
555 bhnd_pmu_request_spuravoid_method(device_t dev, bhnd_pmu_spuravoid spuravoid)
556 {
557 struct bhnd_pmu_softc *sc;
558 int error;
559
560 sc = device_get_softc(dev);
561
562 BPMU_LOCK(sc);
563 error = bhnd_pmu_set_spuravoid(sc, spuravoid);
564 BPMU_UNLOCK(sc);
565
566 return (error);
567 }
568
569 /**
570 * Default bhnd_pmu driver implementation of BHND_PMU_GET_TRANSITION_LATENCY().
571 */
572 static u_int
573 bhnd_pmu_get_max_transition_latency_method(device_t dev)
574 {
575 return (BHND_PMU_MAX_TRANSITION_DLY);
576 }
577
578 /* bhnd_pmu_query read_4 callback */
579 static uint32_t
580 bhnd_pmu_read_4(bus_size_t reg, void *ctx)
581 {
582 struct bhnd_pmu_softc *sc = ctx;
583 return (bhnd_bus_read_4(sc->res, reg));
584 }
585
586 /* bhnd_pmu_query write_4 callback */
587 static void
588 bhnd_pmu_write_4(bus_size_t reg, uint32_t val, void *ctx)
589 {
590 struct bhnd_pmu_softc *sc = ctx;
591 return (bhnd_bus_write_4(sc->res, reg, val));
592 }
593
594 /* bhnd_pmu_query read_chipst callback */
595 static uint32_t
596 bhnd_pmu_read_chipst(void *ctx)
597 {
598 struct bhnd_pmu_softc *sc = ctx;
599 return (BHND_CHIPC_READ_CHIPST(sc->chipc_dev));
600 }
601
602 static device_method_t bhnd_pmu_methods[] = {
603 /* Device interface */
604 DEVMETHOD(device_probe, bhnd_pmu_probe),
605 DEVMETHOD(device_detach, bhnd_pmu_detach),
606 DEVMETHOD(device_suspend, bhnd_pmu_suspend),
607 DEVMETHOD(device_resume, bhnd_pmu_resume),
608
609 /* BHND PMU interface */
610 DEVMETHOD(bhnd_pmu_read_chipctrl, bhnd_pmu_read_chipctrl_method),
611 DEVMETHOD(bhnd_pmu_write_chipctrl, bhnd_pmu_write_chipctrl_method),
612 DEVMETHOD(bhnd_pmu_read_regctrl, bhnd_pmu_read_regctrl_method),
613 DEVMETHOD(bhnd_pmu_write_regctrl, bhnd_pmu_write_regctrl_method),
614 DEVMETHOD(bhnd_pmu_read_pllctrl, bhnd_pmu_read_pllctrl_method),
615 DEVMETHOD(bhnd_pmu_write_pllctrl, bhnd_pmu_write_pllctrl_method),
616 DEVMETHOD(bhnd_pmu_set_voltage_raw, bhnd_pmu_set_voltage_raw_method),
617 DEVMETHOD(bhnd_pmu_enable_regulator, bhnd_pmu_enable_regulator_method),
618 DEVMETHOD(bhnd_pmu_disable_regulator, bhnd_pmu_disable_regulator_method),
619
620 DEVMETHOD(bhnd_pmu_get_clock_latency, bhnd_pmu_get_clock_latency_method),
621 DEVMETHOD(bhnd_pmu_get_clock_freq, bhnd_pmu_get_clock_freq_method),
622
623 DEVMETHOD(bhnd_pmu_get_max_transition_latency, bhnd_pmu_get_max_transition_latency_method),
624 DEVMETHOD(bhnd_pmu_request_spuravoid, bhnd_pmu_request_spuravoid_method),
625
626 DEVMETHOD_END
627 };
628
629 DEFINE_CLASS_0(bhnd_pmu, bhnd_pmu_driver, bhnd_pmu_methods, sizeof(struct bhnd_pmu_softc));
630 MODULE_VERSION(bhnd_pmu, 1);
Cache object: e12124b1f9fc902fefbb07d30007ccce
|