]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/bhnd/cores/pmu/bhnd_pmu.c
Update the GNU DTS file from Linux 4.11
[FreeBSD/FreeBSD.git] / sys / dev / bhnd / cores / pmu / bhnd_pmu.c
1 /*-
2  * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification.
11  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13  *    redistribution must be conditioned upon including a substantially
14  *    similar Disclaimer requirement for further binary redistribution.
15  *
16  * NO WARRANTY
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27  * THE POSSIBILITY OF SUCH DAMAGES.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/kernel.h>
35 #include <sys/lock.h>
36 #include <sys/bus.h>
37 #include <sys/malloc.h>
38 #include <sys/module.h>
39 #include <sys/mutex.h>
40 #include <sys/sysctl.h>
41 #include <sys/systm.h>
42
43 #include <machine/bus.h>
44 #include <machine/resource.h>
45
46 #include <dev/bhnd/bhnd.h>
47 #include <dev/bhnd/cores/chipc/chipc.h>
48
49 #include "bhnd_nvram_map.h"
50
51 #include "bhnd_pmureg.h"
52 #include "bhnd_pmuvar.h"
53
54 #include "bhnd_pmu_private.h"
55
56 /*
57  * Broadcom PMU driver.
58  * 
59  * On modern BHND chipsets, the PMU, GCI, and SRENG (Save/Restore Engine?)
60  * register blocks are found within a dedicated PMU core (attached via
61  * the AHB 'always on bus').
62  * 
63  * On earlier chipsets, these register blocks are found at the same
64  * offsets within the ChipCommon core.
65  */
66
67 devclass_t bhnd_pmu_devclass;   /**< bhnd(4) PMU device class */
68
69 static int      bhnd_pmu_sysctl_bus_freq(SYSCTL_HANDLER_ARGS);
70 static int      bhnd_pmu_sysctl_cpu_freq(SYSCTL_HANDLER_ARGS);
71 static int      bhnd_pmu_sysctl_mem_freq(SYSCTL_HANDLER_ARGS);
72
73 static uint32_t bhnd_pmu_read_4(bus_size_t reg, void *ctx);
74 static void     bhnd_pmu_write_4(bus_size_t reg, uint32_t val, void *ctx);
75 static uint32_t bhnd_pmu_read_chipst(void *ctx);
76
77 static const struct bhnd_pmu_io bhnd_pmu_res_io = {
78         .rd4            = bhnd_pmu_read_4,
79         .wr4            = bhnd_pmu_write_4,
80         .rd_chipst      = bhnd_pmu_read_chipst
81 };
82
83 #define BPMU_ASSERT_CLKCTL_AVAIL(_pinfo)                        \
84         KASSERT(!bhnd_is_hw_suspended((_pinfo)->pm_dev),        \
85             ("reading clkctl on suspended core will trigger system livelock"))
86
87 #define BPMU_CLKCTL_READ_4(_pinfo)              \
88         bhnd_bus_read_4((_pinfo)->pm_res, (_pinfo)->pm_regs)
89
90 #define BPMU_CLKCTL_WRITE_4(_pinfo, _val)       \
91         bhnd_bus_write_4((_pinfo)->pm_res, (_pinfo)->pm_regs, (_val))
92         
93 #define BPMU_CLKCTL_SET_4(_pinfo, _val, _mask)  \
94         BPMU_CLKCTL_WRITE_4((_pinfo),           \
95             ((_val) & (_mask)) | (BPMU_CLKCTL_READ_4(_pinfo) & ~(_mask)))
96
97 /**
98  * Default bhnd_pmu driver implementation of DEVICE_PROBE().
99  */
100 int
101 bhnd_pmu_probe(device_t dev)
102 {
103         return (BUS_PROBE_DEFAULT);
104 }
105
106 /**
107  * Default bhnd_pmu driver implementation of DEVICE_ATTACH().
108  * 
109  * @param dev PMU device.
110  * @param res The PMU device registers. The driver will maintain a borrowed
111  * reference to this resource for the lifetime of the device.
112  */
113 int
114 bhnd_pmu_attach(device_t dev, struct bhnd_resource *res)
115 {
116         struct bhnd_pmu_softc   *sc;
117         struct sysctl_ctx_list  *ctx;
118         struct sysctl_oid       *tree;
119         devclass_t               bhnd_class;
120         device_t                 core, bus;
121         int                      error;
122
123         sc = device_get_softc(dev);
124         sc->dev = dev;
125         sc->quirks = 0;
126         sc->res = res;
127
128         /* Fetch capability flags */
129         sc->caps = bhnd_bus_read_4(sc->res, BHND_PMU_CAP);
130
131         /* Find the bus-attached core */
132         bhnd_class = devclass_find("bhnd");
133         core = sc->dev;
134         while ((bus = device_get_parent(core)) != NULL) {
135                 if (device_get_devclass(bus) == bhnd_class)
136                         break;
137
138                 core = bus;
139         }
140
141         if (core == NULL) {
142                 device_printf(sc->dev, "bhnd bus not found\n");
143                 return (ENXIO);
144         }
145
146         /* Fetch chip and board info */
147         sc->cid = *bhnd_get_chipid(core);
148
149         if ((error = bhnd_read_board_info(core, &sc->board))) {
150                 device_printf(sc->dev, "error fetching board info: %d\n",
151                     error);
152                 return (ENXIO);
153         }
154
155         /* Locate ChipCommon device */
156         sc->chipc_dev = bhnd_find_child(bus, BHND_DEVCLASS_CC, 0);
157         if (sc->chipc_dev == NULL) {
158                 device_printf(sc->dev, "chipcommon device not found\n");
159                 return (ENXIO);
160         }
161
162         /* Initialize query state */
163         error = bhnd_pmu_query_init(&sc->query, dev, sc->cid, &bhnd_pmu_res_io,
164             sc);
165         if (error)
166                 return (error);
167         sc->io = sc->query.io; 
168         sc->io_ctx = sc->query.io_ctx;
169
170         BPMU_LOCK_INIT(sc);
171
172         /* Set quirk flags */
173         switch (sc->cid.chip_id) {
174         case BHND_CHIPID_BCM4328:
175         case BHND_CHIPID_BCM5354:
176                 /* HTAVAIL/ALPAVAIL are bitswapped in CLKCTL */
177                 sc->quirks |= BPMU_QUIRK_CLKCTL_CCS0;
178                 break;
179         default:
180                 break;
181         }
182
183         /* Initialize PMU */
184         if ((error = bhnd_pmu_init(sc))) {
185                 device_printf(sc->dev, "PMU init failed: %d\n", error);
186                 goto failed;
187         }
188
189         /* Set up sysctl nodes */
190         ctx = device_get_sysctl_ctx(dev);
191         tree = device_get_sysctl_tree(dev);
192
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");
196
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");
200         
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");
204
205         return (0);
206
207 failed:
208         BPMU_LOCK_DESTROY(sc);
209         bhnd_pmu_query_fini(&sc->query);
210         return (error);
211 }
212
213 /**
214  * Default bhnd_pmu driver implementation of DEVICE_DETACH().
215  */
216 int
217 bhnd_pmu_detach(device_t dev)
218 {
219         struct bhnd_pmu_softc   *sc;
220
221         sc = device_get_softc(dev);
222
223         BPMU_LOCK_DESTROY(sc);
224         bhnd_pmu_query_fini(&sc->query);
225
226         return (0);
227 }
228
229 /**
230  * Default bhnd_pmu driver implementation of DEVICE_SUSPEND().
231  */
232 int
233 bhnd_pmu_suspend(device_t dev)
234 {
235         return (0);
236 }
237
238 /**
239  * Default bhnd_pmu driver implementation of DEVICE_RESUME().
240  */
241 int
242 bhnd_pmu_resume(device_t dev)
243 {
244         struct bhnd_pmu_softc   *sc;
245         int                      error;
246
247         sc = device_get_softc(dev);
248
249         /* Re-initialize PMU */
250         if ((error = bhnd_pmu_init(sc))) {
251                 device_printf(sc->dev, "PMU init failed: %d\n", error);
252                 return (error);
253         }
254
255         return (0);
256 }
257
258 static int
259 bhnd_pmu_sysctl_bus_freq(SYSCTL_HANDLER_ARGS)
260 {
261         struct bhnd_pmu_softc   *sc;
262         uint32_t                 freq;
263         
264         sc = arg1;
265
266         BPMU_LOCK(sc);
267         freq = bhnd_pmu_si_clock(&sc->query);
268         BPMU_UNLOCK(sc);
269
270         return (sysctl_handle_32(oidp, NULL, freq, req));
271 }
272
273 static int
274 bhnd_pmu_sysctl_cpu_freq(SYSCTL_HANDLER_ARGS)
275 {
276         struct bhnd_pmu_softc   *sc;
277         uint32_t                 freq;
278         
279         sc = arg1;
280
281         BPMU_LOCK(sc);
282         freq = bhnd_pmu_cpu_clock(&sc->query);
283         BPMU_UNLOCK(sc);
284
285         return (sysctl_handle_32(oidp, NULL, freq, req));
286 }
287
288 static int
289 bhnd_pmu_sysctl_mem_freq(SYSCTL_HANDLER_ARGS)
290 {
291         struct bhnd_pmu_softc   *sc;
292         uint32_t                 freq;
293         
294         sc = arg1;
295
296         BPMU_LOCK(sc);
297         freq = bhnd_pmu_mem_clock(&sc->query);
298         BPMU_UNLOCK(sc);
299
300         return (sysctl_handle_32(oidp, NULL, freq, req));
301 }
302
303 static int
304 bhnd_pmu_core_req_clock(device_t dev, struct bhnd_core_pmu_info *pinfo,
305     bhnd_clock clock)
306 {
307         struct bhnd_pmu_softc   *sc;
308         uint32_t                 avail;
309         uint32_t                 req;
310
311         BPMU_ASSERT_CLKCTL_AVAIL(pinfo);
312
313         sc = device_get_softc(dev);
314
315         avail = 0x0;
316         req = 0x0;
317
318         switch (clock) {
319         case BHND_CLOCK_DYN:
320                 break;
321         case BHND_CLOCK_ILP:
322                 req |= BHND_CCS_FORCEILP;
323                 break;
324         case BHND_CLOCK_ALP:
325                 req |= BHND_CCS_FORCEALP;
326                 avail |= BHND_CCS_ALPAVAIL;
327                 break;
328         case BHND_CLOCK_HT:
329                 req |= BHND_CCS_FORCEHT;
330                 avail |= BHND_CCS_HTAVAIL;
331                 break;
332         default:
333                 device_printf(dev, "%s requested unknown clock: %#x\n",
334                     device_get_nameunit(pinfo->pm_dev), clock);
335                 return (ENODEV);
336         }
337
338         BPMU_LOCK(sc);
339
340         /* Issue request */
341         BPMU_CLKCTL_SET_4(pinfo, req, BHND_CCS_FORCE_MASK);
342
343         /* Wait for clock availability */
344         bhnd_pmu_wait_clkst(sc, pinfo->pm_dev, pinfo->pm_res, pinfo->pm_regs,
345             avail, avail);
346
347         BPMU_UNLOCK(sc);
348
349         return (0);
350 }
351
352 static int
353 bhnd_pmu_core_en_clocks(device_t dev, struct bhnd_core_pmu_info *pinfo,
354     uint32_t clocks)
355 {
356         struct bhnd_pmu_softc   *sc;
357         uint32_t                 avail;
358         uint32_t                 req;
359
360         BPMU_ASSERT_CLKCTL_AVAIL(pinfo);
361
362         sc = device_get_softc(dev);
363
364         avail = 0x0;
365         req = 0x0;
366
367         /* Build clock request flags */
368         if (clocks & BHND_CLOCK_DYN)            /* nothing to enable */
369                 clocks &= ~BHND_CLOCK_DYN;
370
371         if (clocks & BHND_CLOCK_ILP)            /* nothing to enable */
372                 clocks &= ~BHND_CLOCK_ILP;
373
374         if (clocks & BHND_CLOCK_ALP) {
375                 req |= BHND_CCS_ALPAREQ;
376                 avail |= BHND_CCS_ALPAVAIL;
377                 clocks &= ~BHND_CLOCK_ALP;
378         }
379
380         if (clocks & BHND_CLOCK_HT) {
381                 req |= BHND_CCS_HTAREQ;
382                 avail |= BHND_CCS_HTAVAIL;
383                 clocks &= ~BHND_CLOCK_HT;
384         }
385
386         /* Check for unknown clock values */
387         if (clocks != 0x0) {
388                 device_printf(dev, "%s requested unknown clocks: %#x\n",
389                     device_get_nameunit(pinfo->pm_dev), clocks);
390                 return (ENODEV);
391         }
392
393         BPMU_LOCK(sc);
394
395         /* Issue request */
396         BPMU_CLKCTL_SET_4(pinfo, req, BHND_CCS_AREQ_MASK);
397
398         /* Wait for clock availability */
399         bhnd_pmu_wait_clkst(sc, pinfo->pm_dev, pinfo->pm_res, pinfo->pm_regs,
400             avail, avail);
401
402         BPMU_UNLOCK(sc);
403
404         return (0);
405 }
406
407 static int
408 bhnd_pmu_core_req_ext_rsrc(device_t dev, struct bhnd_core_pmu_info *pinfo,
409     u_int rsrc)
410 {
411         struct bhnd_pmu_softc   *sc;
412         uint32_t                 req;
413         uint32_t                 avail;
414
415         BPMU_ASSERT_CLKCTL_AVAIL(pinfo);
416
417         sc = device_get_softc(dev);
418
419         if (rsrc > BHND_CCS_ERSRC_MAX)
420                 return (EINVAL);
421
422         req = BHND_PMU_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_REQ);
423         avail = BHND_PMU_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_STS);
424
425         BPMU_LOCK(sc);
426
427         /* Write request */
428         BPMU_CLKCTL_SET_4(pinfo, req, req);
429
430         /* Wait for resource availability */
431         bhnd_pmu_wait_clkst(sc, pinfo->pm_dev, pinfo->pm_res, pinfo->pm_regs,
432             avail, avail);
433
434         BPMU_UNLOCK(sc);
435
436         return (0);     
437 }
438
439 static int
440 bhnd_pmu_core_release_ext_rsrc(device_t dev, struct bhnd_core_pmu_info *pinfo,
441     u_int rsrc)
442 {
443         struct bhnd_pmu_softc   *sc;
444         uint32_t                 mask;
445
446         BPMU_ASSERT_CLKCTL_AVAIL(pinfo);
447
448         sc = device_get_softc(dev);
449
450         if (rsrc > BHND_CCS_ERSRC_MAX)
451                 return (EINVAL);
452
453         mask = BHND_PMU_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_REQ);
454
455         /* Clear request */
456         BPMU_LOCK(sc);
457         BPMU_CLKCTL_SET_4(pinfo, 0x0, mask);
458         BPMU_UNLOCK(sc);
459
460         return (0);     
461 }
462
463 static int
464 bhnd_pmu_core_release(device_t dev, struct bhnd_core_pmu_info *pinfo)
465 {
466         struct bhnd_pmu_softc   *sc;
467
468         sc = device_get_softc(dev);
469
470         /* On PMU-equipped hardware, clkctl is cleared on RESET (and
471          * attempting to access it will trigger a system livelock). */
472         if (bhnd_is_hw_suspended(pinfo->pm_dev))
473                 return (0);
474
475         BPMU_LOCK(sc);
476
477         /* Clear all FORCE, AREQ, and ERSRC flags */
478         BPMU_CLKCTL_SET_4(pinfo, 0x0,
479             BHND_CCS_FORCE_MASK | BHND_CCS_AREQ_MASK | BHND_CCS_ERSRC_REQ_MASK);
480
481         BPMU_UNLOCK(sc);
482
483         return (0);
484 }
485
486 static uint32_t
487 bhnd_pmu_read_4(bus_size_t reg, void *ctx)
488 {
489         struct bhnd_pmu_softc *sc = ctx;
490         return (bhnd_bus_read_4(sc->res, reg));
491 }
492
493 static void
494 bhnd_pmu_write_4(bus_size_t reg, uint32_t val, void *ctx)
495 {
496         struct bhnd_pmu_softc *sc = ctx;
497         return (bhnd_bus_write_4(sc->res, reg, val));
498 }
499
500 static uint32_t
501 bhnd_pmu_read_chipst(void *ctx)
502 {
503         struct bhnd_pmu_softc *sc = ctx;
504         return (BHND_CHIPC_READ_CHIPST(sc->chipc_dev));
505 }
506
507 static device_method_t bhnd_pmu_methods[] = {
508         /* Device interface */
509         DEVMETHOD(device_probe,                 bhnd_pmu_probe),
510         DEVMETHOD(device_detach,                bhnd_pmu_detach),
511         DEVMETHOD(device_suspend,               bhnd_pmu_suspend),
512         DEVMETHOD(device_resume,                bhnd_pmu_resume),
513
514         /* BHND PMU interface */
515         DEVMETHOD(bhnd_pmu_core_req_clock,      bhnd_pmu_core_req_clock),
516         DEVMETHOD(bhnd_pmu_core_en_clocks,      bhnd_pmu_core_en_clocks),
517         DEVMETHOD(bhnd_pmu_core_req_ext_rsrc,   bhnd_pmu_core_req_ext_rsrc),
518         DEVMETHOD(bhnd_pmu_core_release_ext_rsrc, bhnd_pmu_core_release_ext_rsrc),
519         DEVMETHOD(bhnd_pmu_core_release,        bhnd_pmu_core_release),
520
521         DEVMETHOD_END
522 };
523
524 DEFINE_CLASS_0(bhnd_pmu, bhnd_pmu_driver, bhnd_pmu_methods, sizeof(struct bhnd_pmu_softc));
525 MODULE_VERSION(bhnd_pmu, 1);