1b9450e43SRui Paulo /*- 211cede48SLuiz Otavio O Souza * Copyright (C) 2013-2015 Daisuke Aoyama <aoyama@peach.ne.jp> 3b9450e43SRui Paulo * All rights reserved. 4b9450e43SRui Paulo * 5b9450e43SRui Paulo * Redistribution and use in source and binary forms, with or without 6b9450e43SRui Paulo * modification, are permitted provided that the following conditions 7b9450e43SRui Paulo * are met: 8b9450e43SRui Paulo * 1. Redistributions of source code must retain the above copyright 9b9450e43SRui Paulo * notice, this list of conditions and the following disclaimer. 10b9450e43SRui Paulo * 2. Redistributions in binary form must reproduce the above copyright 11b9450e43SRui Paulo * notice, this list of conditions and the following disclaimer in the 12b9450e43SRui Paulo * documentation and/or other materials provided with the distribution. 13b9450e43SRui Paulo * 14b9450e43SRui Paulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15b9450e43SRui Paulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16b9450e43SRui Paulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17b9450e43SRui Paulo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18b9450e43SRui Paulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19b9450e43SRui Paulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20b9450e43SRui Paulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21b9450e43SRui Paulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22b9450e43SRui Paulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23b9450e43SRui Paulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24b9450e43SRui Paulo * SUCH DAMAGE. 25b9450e43SRui Paulo * 26b9450e43SRui Paulo */ 27b9450e43SRui Paulo 28b9450e43SRui Paulo #include <sys/cdefs.h> 29b9450e43SRui Paulo __FBSDID("$FreeBSD$"); 30b9450e43SRui Paulo 31b9450e43SRui Paulo #include <sys/param.h> 32b9450e43SRui Paulo #include <sys/systm.h> 33b9450e43SRui Paulo #include <sys/bus.h> 34b9450e43SRui Paulo #include <sys/cpu.h> 35b9450e43SRui Paulo #include <sys/kernel.h> 36b9450e43SRui Paulo #include <sys/lock.h> 37b9450e43SRui Paulo #include <sys/malloc.h> 38b9450e43SRui Paulo #include <sys/module.h> 39b9450e43SRui Paulo #include <sys/mutex.h> 40b9450e43SRui Paulo #include <sys/sema.h> 41b9450e43SRui Paulo #include <sys/sysctl.h> 42b9450e43SRui Paulo 43b9450e43SRui Paulo #include <machine/bus.h> 44b9450e43SRui Paulo #include <machine/cpu.h> 45b9450e43SRui Paulo #include <machine/intr.h> 46b9450e43SRui Paulo 47b9450e43SRui Paulo #include <arm/broadcom/bcm2835/bcm2835_mbox.h> 48b9450e43SRui Paulo #include <arm/broadcom/bcm2835/bcm2835_mbox_prop.h> 49b9450e43SRui Paulo #include <arm/broadcom/bcm2835/bcm2835_vcbus.h> 50b9450e43SRui Paulo 51b9450e43SRui Paulo #include "cpufreq_if.h" 52b9450e43SRui Paulo #include "mbox_if.h" 53b9450e43SRui Paulo 54b9450e43SRui Paulo #ifdef DEBUG 55b9450e43SRui Paulo #define DPRINTF(fmt, ...) do { \ 56b9450e43SRui Paulo printf("%s:%u: ", __func__, __LINE__); \ 57b9450e43SRui Paulo printf(fmt, ##__VA_ARGS__); \ 58b9450e43SRui Paulo } while (0) 59b9450e43SRui Paulo #else 60b9450e43SRui Paulo #define DPRINTF(fmt, ...) 61b9450e43SRui Paulo #endif 62b9450e43SRui Paulo 63b9450e43SRui Paulo #define HZ2MHZ(freq) ((freq) / (1000 * 1000)) 64b9450e43SRui Paulo #define MHZ2HZ(freq) ((freq) * (1000 * 1000)) 6511cede48SLuiz Otavio O Souza 6611cede48SLuiz Otavio O Souza #ifdef SOC_BCM2836 6711cede48SLuiz Otavio O Souza #define OFFSET2MVOLT(val) (((val) / 1000)) 6811cede48SLuiz Otavio O Souza #define MVOLT2OFFSET(val) (((val) * 1000)) 6911cede48SLuiz Otavio O Souza #define DEFAULT_ARM_FREQUENCY 600 7011cede48SLuiz Otavio O Souza #define DEFAULT_LOWEST_FREQ 600 7111cede48SLuiz Otavio O Souza #else 72b9450e43SRui Paulo #define OFFSET2MVOLT(val) (1200 + ((val) * 25)) 73b9450e43SRui Paulo #define MVOLT2OFFSET(val) (((val) - 1200) / 25) 74b9450e43SRui Paulo #define DEFAULT_ARM_FREQUENCY 700 7511cede48SLuiz Otavio O Souza #define DEFAULT_LOWEST_FREQ 300 7611cede48SLuiz Otavio O Souza #endif 77b9450e43SRui Paulo #define DEFAULT_CORE_FREQUENCY 250 78b9450e43SRui Paulo #define DEFAULT_SDRAM_FREQUENCY 400 79b9450e43SRui Paulo #define TRANSITION_LATENCY 1000 80b9450e43SRui Paulo #define MIN_OVER_VOLTAGE -16 81b9450e43SRui Paulo #define MAX_OVER_VOLTAGE 6 82b9450e43SRui Paulo #define MSG_ERROR -999999999 83b9450e43SRui Paulo #define MHZSTEP 100 84b9450e43SRui Paulo #define HZSTEP (MHZ2HZ(MHZSTEP)) 85e4b6eaf7SLuiz Otavio O Souza #define TZ_ZEROC 2732 86b9450e43SRui Paulo 87b9450e43SRui Paulo #define VC_LOCK(sc) do { \ 88b9450e43SRui Paulo sema_wait(&vc_sema); \ 89b9450e43SRui Paulo } while (0) 90b9450e43SRui Paulo #define VC_UNLOCK(sc) do { \ 91b9450e43SRui Paulo sema_post(&vc_sema); \ 92b9450e43SRui Paulo } while (0) 93b9450e43SRui Paulo 94b9450e43SRui Paulo /* ARM->VC mailbox property semaphore */ 95b9450e43SRui Paulo static struct sema vc_sema; 96b9450e43SRui Paulo 97b9450e43SRui Paulo static struct sysctl_ctx_list bcm2835_sysctl_ctx; 98b9450e43SRui Paulo 99b9450e43SRui Paulo struct bcm2835_cpufreq_softc { 100b9450e43SRui Paulo device_t dev; 101b9450e43SRui Paulo int arm_max_freq; 102b9450e43SRui Paulo int arm_min_freq; 103b9450e43SRui Paulo int core_max_freq; 104b9450e43SRui Paulo int core_min_freq; 105b9450e43SRui Paulo int sdram_max_freq; 106b9450e43SRui Paulo int sdram_min_freq; 107b9450e43SRui Paulo int max_voltage_core; 108b9450e43SRui Paulo int min_voltage_core; 109b9450e43SRui Paulo 110b9450e43SRui Paulo /* the values written in mbox */ 111b9450e43SRui Paulo int voltage_core; 112b9450e43SRui Paulo int voltage_sdram; 113b9450e43SRui Paulo int voltage_sdram_c; 114b9450e43SRui Paulo int voltage_sdram_i; 115b9450e43SRui Paulo int voltage_sdram_p; 116b9450e43SRui Paulo int turbo_mode; 117b9450e43SRui Paulo 118b9450e43SRui Paulo /* mbox buffer (physical address) */ 119b9450e43SRui Paulo bus_dma_tag_t dma_tag; 120b9450e43SRui Paulo bus_dmamap_t dma_map; 121b9450e43SRui Paulo bus_size_t dma_size; 122b9450e43SRui Paulo void *dma_buf; 123b9450e43SRui Paulo bus_addr_t dma_phys; 124b9450e43SRui Paulo 125b9450e43SRui Paulo /* initial hook for waiting mbox intr */ 126b9450e43SRui Paulo struct intr_config_hook init_hook; 127b9450e43SRui Paulo }; 128b9450e43SRui Paulo 129b9450e43SRui Paulo static int cpufreq_verbose = 0; 130b9450e43SRui Paulo TUNABLE_INT("hw.bcm2835.cpufreq.verbose", &cpufreq_verbose); 131b9450e43SRui Paulo static int cpufreq_lowest_freq = DEFAULT_LOWEST_FREQ; 132b9450e43SRui Paulo TUNABLE_INT("hw.bcm2835.cpufreq.lowest_freq", &cpufreq_lowest_freq); 133b9450e43SRui Paulo 134e9faba9dSLuiz Otavio O Souza #ifdef PROP_DEBUG 135b9450e43SRui Paulo static void 136b9450e43SRui Paulo bcm2835_dump(const void *data, int len) 137b9450e43SRui Paulo { 138b9450e43SRui Paulo const uint8_t *p = (const uint8_t*)data; 139b9450e43SRui Paulo int i; 140b9450e43SRui Paulo 141b9450e43SRui Paulo printf("dump @ %p:\n", data); 142b9450e43SRui Paulo for (i = 0; i < len; i++) { 143b9450e43SRui Paulo printf("%2.2x ", p[i]); 144b9450e43SRui Paulo if ((i % 4) == 3) 145b9450e43SRui Paulo printf(" "); 146b9450e43SRui Paulo if ((i % 16) == 15) 147b9450e43SRui Paulo printf("\n"); 148b9450e43SRui Paulo } 149b9450e43SRui Paulo printf("\n"); 150b9450e43SRui Paulo } 151b9450e43SRui Paulo #endif 152b9450e43SRui Paulo 153b9450e43SRui Paulo static int 154b9450e43SRui Paulo bcm2835_mbox_call_prop(struct bcm2835_cpufreq_softc *sc) 155b9450e43SRui Paulo { 156b9450e43SRui Paulo struct bcm2835_mbox_hdr *msg = (struct bcm2835_mbox_hdr *)sc->dma_buf; 157b9450e43SRui Paulo struct bcm2835_mbox_tag_hdr *tag, *last; 158b9450e43SRui Paulo uint8_t *up; 159b9450e43SRui Paulo device_t mbox; 160b9450e43SRui Paulo size_t hdr_size; 161b9450e43SRui Paulo int idx; 162b9450e43SRui Paulo int err; 163b9450e43SRui Paulo 164b9450e43SRui Paulo /* 165b9450e43SRui Paulo * For multiple calls, locking is not here. The caller must have 166b9450e43SRui Paulo * VC semaphore. 167b9450e43SRui Paulo */ 168b9450e43SRui Paulo 169b9450e43SRui Paulo /* get mbox device */ 170b9450e43SRui Paulo mbox = devclass_get_device(devclass_find("mbox"), 0); 171b9450e43SRui Paulo if (mbox == NULL) { 172b9450e43SRui Paulo device_printf(sc->dev, "can't find mbox\n"); 173b9450e43SRui Paulo return (-1); 174b9450e43SRui Paulo } 175b9450e43SRui Paulo 176b9450e43SRui Paulo /* go mailbox property */ 177b9450e43SRui Paulo #ifdef PROP_DEBUG 178b9450e43SRui Paulo bcm2835_dump(msg, 64); 179b9450e43SRui Paulo #endif 180b9450e43SRui Paulo bus_dmamap_sync(sc->dma_tag, sc->dma_map, 181b9450e43SRui Paulo BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 182b9450e43SRui Paulo MBOX_WRITE(mbox, BCM2835_MBOX_CHAN_PROP, (uint32_t)sc->dma_phys); 183b9450e43SRui Paulo MBOX_READ(mbox, BCM2835_MBOX_CHAN_PROP, &err); 184b9450e43SRui Paulo bus_dmamap_sync(sc->dma_tag, sc->dma_map, BUS_DMASYNC_POSTREAD); 185b9450e43SRui Paulo #ifdef PROP_DEBUG 186b9450e43SRui Paulo bcm2835_dump(msg, 64); 187b9450e43SRui Paulo #endif 188b9450e43SRui Paulo 189b9450e43SRui Paulo /* check response code */ 190b9450e43SRui Paulo if (msg->code != BCM2835_MBOX_CODE_RESP_SUCCESS) { 191b9450e43SRui Paulo device_printf(sc->dev, "mbox response error\n"); 192b9450e43SRui Paulo return (-1); 193b9450e43SRui Paulo } 194b9450e43SRui Paulo 195b9450e43SRui Paulo /* tag = first tag */ 196b9450e43SRui Paulo up = (uint8_t *)msg; 197b9450e43SRui Paulo hdr_size = sizeof(struct bcm2835_mbox_hdr); 198b9450e43SRui Paulo tag = (struct bcm2835_mbox_tag_hdr *)(up + hdr_size); 199b9450e43SRui Paulo /* last = end of buffer specified by header */ 200b9450e43SRui Paulo last = (struct bcm2835_mbox_tag_hdr *)(up + msg->buf_size); 201b9450e43SRui Paulo 202b9450e43SRui Paulo /* loop unitl end tag (=0x0) */ 203b9450e43SRui Paulo hdr_size = sizeof(struct bcm2835_mbox_tag_hdr); 204b9450e43SRui Paulo for (idx = 0; tag->tag != 0; idx++) { 205b9450e43SRui Paulo if ((tag->val_len & BCM2835_MBOX_TAG_VAL_LEN_RESPONSE) == 0) { 206b9450e43SRui Paulo device_printf(sc->dev, "tag%d response error\n", idx); 207b9450e43SRui Paulo return (-1); 208b9450e43SRui Paulo } 209b9450e43SRui Paulo /* clear response bit */ 210b9450e43SRui Paulo tag->val_len &= ~BCM2835_MBOX_TAG_VAL_LEN_RESPONSE; 211b9450e43SRui Paulo 212b9450e43SRui Paulo /* get next tag */ 213b9450e43SRui Paulo up = (uint8_t *)tag; 214b9450e43SRui Paulo tag = (struct bcm2835_mbox_tag_hdr *)(up + hdr_size + 215b9450e43SRui Paulo tag->val_buf_size); 216b9450e43SRui Paulo 217b9450e43SRui Paulo /* check buffer size of header */ 218b9450e43SRui Paulo if (tag > last) { 219b9450e43SRui Paulo device_printf(sc->dev, "mbox buffer size error\n"); 220b9450e43SRui Paulo return (-1); 221b9450e43SRui Paulo } 222b9450e43SRui Paulo } 223b9450e43SRui Paulo 224b9450e43SRui Paulo return (0); 225b9450e43SRui Paulo } 226b9450e43SRui Paulo 227b9450e43SRui Paulo static int 228b9450e43SRui Paulo bcm2835_cpufreq_get_clock_rate(struct bcm2835_cpufreq_softc *sc, 229b9450e43SRui Paulo uint32_t clock_id) 230b9450e43SRui Paulo { 231b9450e43SRui Paulo struct msg_get_clock_rate *msg; 232b9450e43SRui Paulo int rate; 233b9450e43SRui Paulo int err; 234b9450e43SRui Paulo 235b9450e43SRui Paulo /* 236b9450e43SRui Paulo * Get clock rate 237b9450e43SRui Paulo * Tag: 0x00030002 238b9450e43SRui Paulo * Request: 239b9450e43SRui Paulo * Length: 4 240b9450e43SRui Paulo * Value: 241b9450e43SRui Paulo * u32: clock id 242b9450e43SRui Paulo * Response: 243b9450e43SRui Paulo * Length: 8 244b9450e43SRui Paulo * Value: 245b9450e43SRui Paulo * u32: clock id 246b9450e43SRui Paulo * u32: rate (in Hz) 247b9450e43SRui Paulo */ 248b9450e43SRui Paulo 249b9450e43SRui Paulo /* using DMA buffer for VC */ 250b9450e43SRui Paulo msg = (struct msg_get_clock_rate *)sc->dma_buf; 251b9450e43SRui Paulo if (sizeof(*msg) > sc->dma_size) { 252b9450e43SRui Paulo device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n", 253b9450e43SRui Paulo sizeof(*msg), sc->dma_size); 254b9450e43SRui Paulo return (MSG_ERROR); 255b9450e43SRui Paulo } 256b9450e43SRui Paulo 257b9450e43SRui Paulo /* setup single tag buffer */ 258b9450e43SRui Paulo memset(msg, 0, sizeof(*msg)); 259b9450e43SRui Paulo msg->hdr.buf_size = sizeof(*msg); 260b9450e43SRui Paulo msg->hdr.code = BCM2835_MBOX_CODE_REQ; 261b9450e43SRui Paulo msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_CLOCK_RATE; 262b9450e43SRui Paulo msg->tag_hdr.val_buf_size = sizeof(msg->body); 263b9450e43SRui Paulo msg->tag_hdr.val_len = sizeof(msg->body.req); 264b9450e43SRui Paulo msg->body.req.clock_id = clock_id; 265b9450e43SRui Paulo msg->end_tag = 0; 266b9450e43SRui Paulo 267b9450e43SRui Paulo /* call mailbox property */ 268b9450e43SRui Paulo err = bcm2835_mbox_call_prop(sc); 269b9450e43SRui Paulo if (err) { 270b9450e43SRui Paulo device_printf(sc->dev, "can't get clock rate (id=%u)\n", 271b9450e43SRui Paulo clock_id); 272b9450e43SRui Paulo return (MSG_ERROR); 273b9450e43SRui Paulo } 274b9450e43SRui Paulo 275b9450e43SRui Paulo /* result (Hz) */ 276b9450e43SRui Paulo rate = (int)msg->body.resp.rate_hz; 277b9450e43SRui Paulo DPRINTF("clock = %d(Hz)\n", rate); 278b9450e43SRui Paulo return (rate); 279b9450e43SRui Paulo } 280b9450e43SRui Paulo 281b9450e43SRui Paulo static int 282b9450e43SRui Paulo bcm2835_cpufreq_get_max_clock_rate(struct bcm2835_cpufreq_softc *sc, 283b9450e43SRui Paulo uint32_t clock_id) 284b9450e43SRui Paulo { 285b9450e43SRui Paulo struct msg_get_max_clock_rate *msg; 286b9450e43SRui Paulo int rate; 287b9450e43SRui Paulo int err; 288b9450e43SRui Paulo 289b9450e43SRui Paulo /* 290b9450e43SRui Paulo * Get max clock rate 291b9450e43SRui Paulo * Tag: 0x00030004 292b9450e43SRui Paulo * Request: 293b9450e43SRui Paulo * Length: 4 294b9450e43SRui Paulo * Value: 295b9450e43SRui Paulo * u32: clock id 296b9450e43SRui Paulo * Response: 297b9450e43SRui Paulo * Length: 8 298b9450e43SRui Paulo * Value: 299b9450e43SRui Paulo * u32: clock id 300b9450e43SRui Paulo * u32: rate (in Hz) 301b9450e43SRui Paulo */ 302b9450e43SRui Paulo 303b9450e43SRui Paulo /* using DMA buffer for VC */ 304b9450e43SRui Paulo msg = (struct msg_get_max_clock_rate *)sc->dma_buf; 305b9450e43SRui Paulo if (sizeof(*msg) > sc->dma_size) { 306b9450e43SRui Paulo device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n", 307b9450e43SRui Paulo sizeof(*msg), sc->dma_size); 308b9450e43SRui Paulo return (MSG_ERROR); 309b9450e43SRui Paulo } 310b9450e43SRui Paulo 311b9450e43SRui Paulo /* setup single tag buffer */ 312b9450e43SRui Paulo memset(msg, 0, sizeof(*msg)); 313b9450e43SRui Paulo msg->hdr.buf_size = sizeof(*msg); 314b9450e43SRui Paulo msg->hdr.code = BCM2835_MBOX_CODE_REQ; 315b9450e43SRui Paulo msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_MAX_CLOCK_RATE; 316b9450e43SRui Paulo msg->tag_hdr.val_buf_size = sizeof(msg->body); 317b9450e43SRui Paulo msg->tag_hdr.val_len = sizeof(msg->body.req); 318b9450e43SRui Paulo msg->body.req.clock_id = clock_id; 319b9450e43SRui Paulo msg->end_tag = 0; 320b9450e43SRui Paulo 321b9450e43SRui Paulo /* call mailbox property */ 322b9450e43SRui Paulo err = bcm2835_mbox_call_prop(sc); 323b9450e43SRui Paulo if (err) { 324b9450e43SRui Paulo device_printf(sc->dev, "can't get max clock rate (id=%u)\n", 325b9450e43SRui Paulo clock_id); 326b9450e43SRui Paulo return (MSG_ERROR); 327b9450e43SRui Paulo } 328b9450e43SRui Paulo 329b9450e43SRui Paulo /* result (Hz) */ 330b9450e43SRui Paulo rate = (int)msg->body.resp.rate_hz; 331b9450e43SRui Paulo DPRINTF("clock = %d(Hz)\n", rate); 332b9450e43SRui Paulo return (rate); 333b9450e43SRui Paulo } 334b9450e43SRui Paulo 335b9450e43SRui Paulo static int 336b9450e43SRui Paulo bcm2835_cpufreq_get_min_clock_rate(struct bcm2835_cpufreq_softc *sc, 337b9450e43SRui Paulo uint32_t clock_id) 338b9450e43SRui Paulo { 339b9450e43SRui Paulo struct msg_get_min_clock_rate *msg; 340b9450e43SRui Paulo int rate; 341b9450e43SRui Paulo int err; 342b9450e43SRui Paulo 343b9450e43SRui Paulo /* 344b9450e43SRui Paulo * Get min clock rate 345b9450e43SRui Paulo * Tag: 0x00030007 346b9450e43SRui Paulo * Request: 347b9450e43SRui Paulo * Length: 4 348b9450e43SRui Paulo * Value: 349b9450e43SRui Paulo * u32: clock id 350b9450e43SRui Paulo * Response: 351b9450e43SRui Paulo * Length: 8 352b9450e43SRui Paulo * Value: 353b9450e43SRui Paulo * u32: clock id 354b9450e43SRui Paulo * u32: rate (in Hz) 355b9450e43SRui Paulo */ 356b9450e43SRui Paulo 357b9450e43SRui Paulo /* using DMA buffer for VC */ 358b9450e43SRui Paulo msg = (struct msg_get_min_clock_rate *)sc->dma_buf; 359b9450e43SRui Paulo if (sizeof(*msg) > sc->dma_size) { 360b9450e43SRui Paulo device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n", 361b9450e43SRui Paulo sizeof(*msg), sc->dma_size); 362b9450e43SRui Paulo return (MSG_ERROR); 363b9450e43SRui Paulo } 364b9450e43SRui Paulo 365b9450e43SRui Paulo /* setup single tag buffer */ 366b9450e43SRui Paulo memset(msg, 0, sizeof(*msg)); 367b9450e43SRui Paulo msg->hdr.buf_size = sizeof(*msg); 368b9450e43SRui Paulo msg->hdr.code = BCM2835_MBOX_CODE_REQ; 369b9450e43SRui Paulo msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_MIN_CLOCK_RATE; 370b9450e43SRui Paulo msg->tag_hdr.val_buf_size = sizeof(msg->body); 371b9450e43SRui Paulo msg->tag_hdr.val_len = sizeof(msg->body.req); 372b9450e43SRui Paulo msg->body.req.clock_id = clock_id; 373b9450e43SRui Paulo msg->end_tag = 0; 374b9450e43SRui Paulo 375b9450e43SRui Paulo /* call mailbox property */ 376b9450e43SRui Paulo err = bcm2835_mbox_call_prop(sc); 377b9450e43SRui Paulo if (err) { 378b9450e43SRui Paulo device_printf(sc->dev, "can't get min clock rate (id=%u)\n", 379b9450e43SRui Paulo clock_id); 380b9450e43SRui Paulo return (MSG_ERROR); 381b9450e43SRui Paulo } 382b9450e43SRui Paulo 383b9450e43SRui Paulo /* result (Hz) */ 384b9450e43SRui Paulo rate = (int)msg->body.resp.rate_hz; 385b9450e43SRui Paulo DPRINTF("clock = %d(Hz)\n", rate); 386b9450e43SRui Paulo return (rate); 387b9450e43SRui Paulo } 388b9450e43SRui Paulo 389b9450e43SRui Paulo static int 390b9450e43SRui Paulo bcm2835_cpufreq_set_clock_rate(struct bcm2835_cpufreq_softc *sc, 391b9450e43SRui Paulo uint32_t clock_id, uint32_t rate_hz) 392b9450e43SRui Paulo { 393b9450e43SRui Paulo struct msg_set_clock_rate *msg; 394b9450e43SRui Paulo int rate; 395b9450e43SRui Paulo int err; 396b9450e43SRui Paulo 397b9450e43SRui Paulo /* 398b9450e43SRui Paulo * Set clock rate 399b9450e43SRui Paulo * Tag: 0x00038002 400b9450e43SRui Paulo * Request: 401b9450e43SRui Paulo * Length: 8 402b9450e43SRui Paulo * Value: 403b9450e43SRui Paulo * u32: clock id 404b9450e43SRui Paulo * u32: rate (in Hz) 405b9450e43SRui Paulo * Response: 406b9450e43SRui Paulo * Length: 8 407b9450e43SRui Paulo * Value: 408b9450e43SRui Paulo * u32: clock id 409b9450e43SRui Paulo * u32: rate (in Hz) 410b9450e43SRui Paulo */ 411b9450e43SRui Paulo 412b9450e43SRui Paulo /* using DMA buffer for VC */ 413b9450e43SRui Paulo msg = (struct msg_set_clock_rate *)sc->dma_buf; 414b9450e43SRui Paulo if (sizeof(*msg) > sc->dma_size) { 415b9450e43SRui Paulo device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n", 416b9450e43SRui Paulo sizeof(*msg), sc->dma_size); 417b9450e43SRui Paulo return (MSG_ERROR); 418b9450e43SRui Paulo } 419b9450e43SRui Paulo 420b9450e43SRui Paulo /* setup single tag buffer */ 421b9450e43SRui Paulo memset(msg, 0, sizeof(*msg)); 422b9450e43SRui Paulo msg->hdr.buf_size = sizeof(*msg); 423b9450e43SRui Paulo msg->hdr.code = BCM2835_MBOX_CODE_REQ; 424b9450e43SRui Paulo msg->tag_hdr.tag = BCM2835_MBOX_TAG_SET_CLOCK_RATE; 425b9450e43SRui Paulo msg->tag_hdr.val_buf_size = sizeof(msg->body); 426b9450e43SRui Paulo msg->tag_hdr.val_len = sizeof(msg->body.req); 427b9450e43SRui Paulo msg->body.req.clock_id = clock_id; 428b9450e43SRui Paulo msg->body.req.rate_hz = rate_hz; 429b9450e43SRui Paulo msg->end_tag = 0; 430b9450e43SRui Paulo 431b9450e43SRui Paulo /* call mailbox property */ 432b9450e43SRui Paulo err = bcm2835_mbox_call_prop(sc); 433b9450e43SRui Paulo if (err) { 434b9450e43SRui Paulo device_printf(sc->dev, "can't set clock rate (id=%u)\n", 435b9450e43SRui Paulo clock_id); 436b9450e43SRui Paulo return (MSG_ERROR); 437b9450e43SRui Paulo } 438b9450e43SRui Paulo 439b9450e43SRui Paulo /* workaround for core clock */ 440b9450e43SRui Paulo if (clock_id == BCM2835_MBOX_CLOCK_ID_CORE) { 441b9450e43SRui Paulo /* for safety (may change voltage without changing clock) */ 442b9450e43SRui Paulo DELAY(TRANSITION_LATENCY); 443b9450e43SRui Paulo 444b9450e43SRui Paulo /* 445b9450e43SRui Paulo * XXX: the core clock is unable to change at once, 446b9450e43SRui Paulo * to change certainly, write it twice now. 447b9450e43SRui Paulo */ 448b9450e43SRui Paulo 449b9450e43SRui Paulo /* setup single tag buffer */ 450b9450e43SRui Paulo memset(msg, 0, sizeof(*msg)); 451b9450e43SRui Paulo msg->hdr.buf_size = sizeof(*msg); 452b9450e43SRui Paulo msg->hdr.code = BCM2835_MBOX_CODE_REQ; 453b9450e43SRui Paulo msg->tag_hdr.tag = BCM2835_MBOX_TAG_SET_CLOCK_RATE; 454b9450e43SRui Paulo msg->tag_hdr.val_buf_size = sizeof(msg->body); 455b9450e43SRui Paulo msg->tag_hdr.val_len = sizeof(msg->body.req); 456b9450e43SRui Paulo msg->body.req.clock_id = clock_id; 457b9450e43SRui Paulo msg->body.req.rate_hz = rate_hz; 458b9450e43SRui Paulo msg->end_tag = 0; 459b9450e43SRui Paulo 460b9450e43SRui Paulo /* call mailbox property */ 461b9450e43SRui Paulo err = bcm2835_mbox_call_prop(sc); 462b9450e43SRui Paulo if (err) { 463b9450e43SRui Paulo device_printf(sc->dev, 464b9450e43SRui Paulo "can't set clock rate (id=%u)\n", clock_id); 465b9450e43SRui Paulo return (MSG_ERROR); 466b9450e43SRui Paulo } 467b9450e43SRui Paulo } 468b9450e43SRui Paulo 469b9450e43SRui Paulo /* result (Hz) */ 470b9450e43SRui Paulo rate = (int)msg->body.resp.rate_hz; 471b9450e43SRui Paulo DPRINTF("clock = %d(Hz)\n", rate); 472b9450e43SRui Paulo return (rate); 473b9450e43SRui Paulo } 474b9450e43SRui Paulo 475b9450e43SRui Paulo static int 476b9450e43SRui Paulo bcm2835_cpufreq_get_turbo(struct bcm2835_cpufreq_softc *sc) 477b9450e43SRui Paulo { 478b9450e43SRui Paulo struct msg_get_turbo *msg; 479b9450e43SRui Paulo int level; 480b9450e43SRui Paulo int err; 481b9450e43SRui Paulo 482b9450e43SRui Paulo /* 483b9450e43SRui Paulo * Get turbo 484b9450e43SRui Paulo * Tag: 0x00030009 485b9450e43SRui Paulo * Request: 486b9450e43SRui Paulo * Length: 4 487b9450e43SRui Paulo * Value: 488b9450e43SRui Paulo * u32: id 489b9450e43SRui Paulo * Response: 490b9450e43SRui Paulo * Length: 8 491b9450e43SRui Paulo * Value: 492b9450e43SRui Paulo * u32: id 493b9450e43SRui Paulo * u32: level 494b9450e43SRui Paulo */ 495b9450e43SRui Paulo 496b9450e43SRui Paulo /* using DMA buffer for VC */ 497b9450e43SRui Paulo msg = (struct msg_get_turbo *)sc->dma_buf; 498b9450e43SRui Paulo if (sizeof(*msg) > sc->dma_size) { 499b9450e43SRui Paulo device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n", 500b9450e43SRui Paulo sizeof(*msg), sc->dma_size); 501b9450e43SRui Paulo return (MSG_ERROR); 502b9450e43SRui Paulo } 503b9450e43SRui Paulo 504b9450e43SRui Paulo /* setup single tag buffer */ 505b9450e43SRui Paulo memset(msg, 0, sizeof(*msg)); 506b9450e43SRui Paulo msg->hdr.buf_size = sizeof(*msg); 507b9450e43SRui Paulo msg->hdr.code = BCM2835_MBOX_CODE_REQ; 508b9450e43SRui Paulo msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_TURBO; 509b9450e43SRui Paulo msg->tag_hdr.val_buf_size = sizeof(msg->body); 510b9450e43SRui Paulo msg->tag_hdr.val_len = sizeof(msg->body.req); 511b9450e43SRui Paulo msg->body.req.id = 0; 512b9450e43SRui Paulo msg->end_tag = 0; 513b9450e43SRui Paulo 514b9450e43SRui Paulo /* call mailbox property */ 515b9450e43SRui Paulo err = bcm2835_mbox_call_prop(sc); 516b9450e43SRui Paulo if (err) { 517b9450e43SRui Paulo device_printf(sc->dev, "can't get turbo\n"); 518b9450e43SRui Paulo return (MSG_ERROR); 519b9450e43SRui Paulo } 520b9450e43SRui Paulo 521b9450e43SRui Paulo /* result 0=non-turbo, 1=turbo */ 522b9450e43SRui Paulo level = (int)msg->body.resp.level; 523b9450e43SRui Paulo DPRINTF("level = %d\n", level); 524b9450e43SRui Paulo return (level); 525b9450e43SRui Paulo } 526b9450e43SRui Paulo 527b9450e43SRui Paulo static int 528b9450e43SRui Paulo bcm2835_cpufreq_set_turbo(struct bcm2835_cpufreq_softc *sc, uint32_t level) 529b9450e43SRui Paulo { 530b9450e43SRui Paulo struct msg_set_turbo *msg; 531b9450e43SRui Paulo int value; 532b9450e43SRui Paulo int err; 533b9450e43SRui Paulo 534b9450e43SRui Paulo /* 535b9450e43SRui Paulo * Set turbo 536b9450e43SRui Paulo * Tag: 0x00038009 537b9450e43SRui Paulo * Request: 538b9450e43SRui Paulo * Length: 8 539b9450e43SRui Paulo * Value: 540b9450e43SRui Paulo * u32: id 541b9450e43SRui Paulo * u32: level 542b9450e43SRui Paulo * Response: 543b9450e43SRui Paulo * Length: 8 544b9450e43SRui Paulo * Value: 545b9450e43SRui Paulo * u32: id 546b9450e43SRui Paulo * u32: level 547b9450e43SRui Paulo */ 548b9450e43SRui Paulo 549b9450e43SRui Paulo /* using DMA buffer for VC */ 550b9450e43SRui Paulo msg = (struct msg_set_turbo *)sc->dma_buf; 551b9450e43SRui Paulo if (sizeof(*msg) > sc->dma_size) { 552b9450e43SRui Paulo device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n", 553b9450e43SRui Paulo sizeof(*msg), sc->dma_size); 554b9450e43SRui Paulo return (MSG_ERROR); 555b9450e43SRui Paulo } 556b9450e43SRui Paulo 557b9450e43SRui Paulo /* replace unknown value to OFF */ 558b9450e43SRui Paulo if (level != BCM2835_MBOX_TURBO_ON && level != BCM2835_MBOX_TURBO_OFF) 559b9450e43SRui Paulo level = BCM2835_MBOX_TURBO_OFF; 560b9450e43SRui Paulo 561b9450e43SRui Paulo /* setup single tag buffer */ 562b9450e43SRui Paulo memset(msg, 0, sizeof(*msg)); 563b9450e43SRui Paulo msg->hdr.buf_size = sizeof(*msg); 564b9450e43SRui Paulo msg->hdr.code = BCM2835_MBOX_CODE_REQ; 565b9450e43SRui Paulo msg->tag_hdr.tag = BCM2835_MBOX_TAG_SET_TURBO; 566b9450e43SRui Paulo msg->tag_hdr.val_buf_size = sizeof(msg->body); 567b9450e43SRui Paulo msg->tag_hdr.val_len = sizeof(msg->body.req); 568b9450e43SRui Paulo msg->body.req.id = 0; 569b9450e43SRui Paulo msg->body.req.level = level; 570b9450e43SRui Paulo msg->end_tag = 0; 571b9450e43SRui Paulo 572b9450e43SRui Paulo /* call mailbox property */ 573b9450e43SRui Paulo err = bcm2835_mbox_call_prop(sc); 574b9450e43SRui Paulo if (err) { 575b9450e43SRui Paulo device_printf(sc->dev, "can't set turbo\n"); 576b9450e43SRui Paulo return (MSG_ERROR); 577b9450e43SRui Paulo } 578b9450e43SRui Paulo 579b9450e43SRui Paulo /* result 0=non-turbo, 1=turbo */ 580b9450e43SRui Paulo value = (int)msg->body.resp.level; 581b9450e43SRui Paulo DPRINTF("level = %d\n", value); 582b9450e43SRui Paulo return (value); 583b9450e43SRui Paulo } 584b9450e43SRui Paulo 585b9450e43SRui Paulo static int 586b9450e43SRui Paulo bcm2835_cpufreq_get_voltage(struct bcm2835_cpufreq_softc *sc, 587b9450e43SRui Paulo uint32_t voltage_id) 588b9450e43SRui Paulo { 589b9450e43SRui Paulo struct msg_get_voltage *msg; 590b9450e43SRui Paulo int value; 591b9450e43SRui Paulo int err; 592b9450e43SRui Paulo 593b9450e43SRui Paulo /* 594b9450e43SRui Paulo * Get voltage 595b9450e43SRui Paulo * Tag: 0x00030003 596b9450e43SRui Paulo * Request: 597b9450e43SRui Paulo * Length: 4 598b9450e43SRui Paulo * Value: 599b9450e43SRui Paulo * u32: voltage id 600b9450e43SRui Paulo * Response: 601b9450e43SRui Paulo * Length: 8 602b9450e43SRui Paulo * Value: 603b9450e43SRui Paulo * u32: voltage id 604b9450e43SRui Paulo * u32: value (offset from 1.2V in units of 0.025V) 605b9450e43SRui Paulo */ 606b9450e43SRui Paulo 607b9450e43SRui Paulo /* using DMA buffer for VC */ 608b9450e43SRui Paulo msg = (struct msg_get_voltage *)sc->dma_buf; 609b9450e43SRui Paulo if (sizeof(*msg) > sc->dma_size) { 610b9450e43SRui Paulo device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n", 611b9450e43SRui Paulo sizeof(*msg), sc->dma_size); 612b9450e43SRui Paulo return (MSG_ERROR); 613b9450e43SRui Paulo } 614b9450e43SRui Paulo 615b9450e43SRui Paulo /* setup single tag buffer */ 616b9450e43SRui Paulo memset(msg, 0, sizeof(*msg)); 617b9450e43SRui Paulo msg->hdr.buf_size = sizeof(*msg); 618b9450e43SRui Paulo msg->hdr.code = BCM2835_MBOX_CODE_REQ; 619b9450e43SRui Paulo msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_VOLTAGE; 620b9450e43SRui Paulo msg->tag_hdr.val_buf_size = sizeof(msg->body); 621b9450e43SRui Paulo msg->tag_hdr.val_len = sizeof(msg->body.req); 622b9450e43SRui Paulo msg->body.req.voltage_id = voltage_id; 623b9450e43SRui Paulo msg->end_tag = 0; 624b9450e43SRui Paulo 625b9450e43SRui Paulo /* call mailbox property */ 626b9450e43SRui Paulo err = bcm2835_mbox_call_prop(sc); 627b9450e43SRui Paulo if (err) { 628b9450e43SRui Paulo device_printf(sc->dev, "can't get voltage\n"); 629b9450e43SRui Paulo return (MSG_ERROR); 630b9450e43SRui Paulo } 631b9450e43SRui Paulo 632b9450e43SRui Paulo /* result (offset from 1.2V) */ 633b9450e43SRui Paulo value = (int)msg->body.resp.value; 634b9450e43SRui Paulo DPRINTF("value = %d\n", value); 635b9450e43SRui Paulo return (value); 636b9450e43SRui Paulo } 637b9450e43SRui Paulo 638b9450e43SRui Paulo static int 639b9450e43SRui Paulo bcm2835_cpufreq_get_max_voltage(struct bcm2835_cpufreq_softc *sc, 640b9450e43SRui Paulo uint32_t voltage_id) 641b9450e43SRui Paulo { 642b9450e43SRui Paulo struct msg_get_max_voltage *msg; 643b9450e43SRui Paulo int value; 644b9450e43SRui Paulo int err; 645b9450e43SRui Paulo 646b9450e43SRui Paulo /* 647b9450e43SRui Paulo * Get voltage 648b9450e43SRui Paulo * Tag: 0x00030005 649b9450e43SRui Paulo * Request: 650b9450e43SRui Paulo * Length: 4 651b9450e43SRui Paulo * Value: 652b9450e43SRui Paulo * u32: voltage id 653b9450e43SRui Paulo * Response: 654b9450e43SRui Paulo * Length: 8 655b9450e43SRui Paulo * Value: 656b9450e43SRui Paulo * u32: voltage id 657b9450e43SRui Paulo * u32: value (offset from 1.2V in units of 0.025V) 658b9450e43SRui Paulo */ 659b9450e43SRui Paulo 660b9450e43SRui Paulo /* using DMA buffer for VC */ 661b9450e43SRui Paulo msg = (struct msg_get_max_voltage *)sc->dma_buf; 662b9450e43SRui Paulo if (sizeof(*msg) > sc->dma_size) { 663b9450e43SRui Paulo device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n", 664b9450e43SRui Paulo sizeof(*msg), sc->dma_size); 665b9450e43SRui Paulo return (MSG_ERROR); 666b9450e43SRui Paulo } 667b9450e43SRui Paulo 668b9450e43SRui Paulo /* setup single tag buffer */ 669b9450e43SRui Paulo memset(msg, 0, sizeof(*msg)); 670b9450e43SRui Paulo msg->hdr.buf_size = sizeof(*msg); 671b9450e43SRui Paulo msg->hdr.code = BCM2835_MBOX_CODE_REQ; 672b9450e43SRui Paulo msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_MAX_VOLTAGE; 673b9450e43SRui Paulo msg->tag_hdr.val_buf_size = sizeof(msg->body); 674b9450e43SRui Paulo msg->tag_hdr.val_len = sizeof(msg->body.req); 675b9450e43SRui Paulo msg->body.req.voltage_id = voltage_id; 676b9450e43SRui Paulo msg->end_tag = 0; 677b9450e43SRui Paulo 678b9450e43SRui Paulo /* call mailbox property */ 679b9450e43SRui Paulo err = bcm2835_mbox_call_prop(sc); 680b9450e43SRui Paulo if (err) { 681b9450e43SRui Paulo device_printf(sc->dev, "can't get max voltage\n"); 682b9450e43SRui Paulo return (MSG_ERROR); 683b9450e43SRui Paulo } 684b9450e43SRui Paulo 685b9450e43SRui Paulo /* result (offset from 1.2V) */ 686b9450e43SRui Paulo value = (int)msg->body.resp.value; 687b9450e43SRui Paulo DPRINTF("value = %d\n", value); 688b9450e43SRui Paulo return (value); 689b9450e43SRui Paulo } 690b9450e43SRui Paulo static int 691b9450e43SRui Paulo bcm2835_cpufreq_get_min_voltage(struct bcm2835_cpufreq_softc *sc, 692b9450e43SRui Paulo uint32_t voltage_id) 693b9450e43SRui Paulo { 694b9450e43SRui Paulo struct msg_get_min_voltage *msg; 695b9450e43SRui Paulo int value; 696b9450e43SRui Paulo int err; 697b9450e43SRui Paulo 698b9450e43SRui Paulo /* 699b9450e43SRui Paulo * Get voltage 700b9450e43SRui Paulo * Tag: 0x00030008 701b9450e43SRui Paulo * Request: 702b9450e43SRui Paulo * Length: 4 703b9450e43SRui Paulo * Value: 704b9450e43SRui Paulo * u32: voltage id 705b9450e43SRui Paulo * Response: 706b9450e43SRui Paulo * Length: 8 707b9450e43SRui Paulo * Value: 708b9450e43SRui Paulo * u32: voltage id 709b9450e43SRui Paulo * u32: value (offset from 1.2V in units of 0.025V) 710b9450e43SRui Paulo */ 711b9450e43SRui Paulo 712b9450e43SRui Paulo /* using DMA buffer for VC */ 713b9450e43SRui Paulo msg = (struct msg_get_min_voltage *)sc->dma_buf; 714b9450e43SRui Paulo if (sizeof(*msg) > sc->dma_size) { 715b9450e43SRui Paulo device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n", 716b9450e43SRui Paulo sizeof(*msg), sc->dma_size); 717b9450e43SRui Paulo return (MSG_ERROR); 718b9450e43SRui Paulo } 719b9450e43SRui Paulo 720b9450e43SRui Paulo /* setup single tag buffer */ 721b9450e43SRui Paulo memset(msg, 0, sizeof(*msg)); 722b9450e43SRui Paulo msg->hdr.buf_size = sizeof(*msg); 723b9450e43SRui Paulo msg->hdr.code = BCM2835_MBOX_CODE_REQ; 724b9450e43SRui Paulo msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_MIN_VOLTAGE; 725b9450e43SRui Paulo msg->tag_hdr.val_buf_size = sizeof(msg->body); 726b9450e43SRui Paulo msg->tag_hdr.val_len = sizeof(msg->body.req); 727b9450e43SRui Paulo msg->body.req.voltage_id = voltage_id; 728b9450e43SRui Paulo msg->end_tag = 0; 729b9450e43SRui Paulo 730b9450e43SRui Paulo /* call mailbox property */ 731b9450e43SRui Paulo err = bcm2835_mbox_call_prop(sc); 732b9450e43SRui Paulo if (err) { 733b9450e43SRui Paulo device_printf(sc->dev, "can't get min voltage\n"); 734b9450e43SRui Paulo return (MSG_ERROR); 735b9450e43SRui Paulo } 736b9450e43SRui Paulo 737b9450e43SRui Paulo /* result (offset from 1.2V) */ 738b9450e43SRui Paulo value = (int)msg->body.resp.value; 739b9450e43SRui Paulo DPRINTF("value = %d\n", value); 740b9450e43SRui Paulo return (value); 741b9450e43SRui Paulo } 742b9450e43SRui Paulo 743b9450e43SRui Paulo static int 744b9450e43SRui Paulo bcm2835_cpufreq_set_voltage(struct bcm2835_cpufreq_softc *sc, 745b9450e43SRui Paulo uint32_t voltage_id, int32_t value) 746b9450e43SRui Paulo { 747b9450e43SRui Paulo struct msg_set_voltage *msg; 748b9450e43SRui Paulo int err; 749b9450e43SRui Paulo 750b9450e43SRui Paulo /* 751b9450e43SRui Paulo * Set voltage 752b9450e43SRui Paulo * Tag: 0x00038003 753b9450e43SRui Paulo * Request: 754b9450e43SRui Paulo * Length: 4 755b9450e43SRui Paulo * Value: 756b9450e43SRui Paulo * u32: voltage id 757b9450e43SRui Paulo * u32: value (offset from 1.2V in units of 0.025V) 758b9450e43SRui Paulo * Response: 759b9450e43SRui Paulo * Length: 8 760b9450e43SRui Paulo * Value: 761b9450e43SRui Paulo * u32: voltage id 762b9450e43SRui Paulo * u32: value (offset from 1.2V in units of 0.025V) 763b9450e43SRui Paulo */ 764b9450e43SRui Paulo 765b9450e43SRui Paulo /* 766b9450e43SRui Paulo * over_voltage: 767b9450e43SRui Paulo * 0 (1.2 V). Values above 6 are only allowed when force_turbo or 768b9450e43SRui Paulo * current_limit_override are specified (which set the warranty bit). 769b9450e43SRui Paulo */ 770b9450e43SRui Paulo if (value > MAX_OVER_VOLTAGE || value < MIN_OVER_VOLTAGE) { 771b9450e43SRui Paulo /* currently not supported */ 772b9450e43SRui Paulo device_printf(sc->dev, "not supported voltage: %d\n", value); 773b9450e43SRui Paulo return (MSG_ERROR); 774b9450e43SRui Paulo } 775b9450e43SRui Paulo 776b9450e43SRui Paulo /* using DMA buffer for VC */ 777b9450e43SRui Paulo msg = (struct msg_set_voltage *)sc->dma_buf; 778b9450e43SRui Paulo if (sizeof(*msg) > sc->dma_size) { 779b9450e43SRui Paulo device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n", 780b9450e43SRui Paulo sizeof(*msg), sc->dma_size); 781b9450e43SRui Paulo return (MSG_ERROR); 782b9450e43SRui Paulo } 783b9450e43SRui Paulo 784b9450e43SRui Paulo /* setup single tag buffer */ 785b9450e43SRui Paulo memset(msg, 0, sizeof(*msg)); 786b9450e43SRui Paulo msg->hdr.buf_size = sizeof(*msg); 787b9450e43SRui Paulo msg->hdr.code = BCM2835_MBOX_CODE_REQ; 788b9450e43SRui Paulo msg->tag_hdr.tag = BCM2835_MBOX_TAG_SET_VOLTAGE; 789b9450e43SRui Paulo msg->tag_hdr.val_buf_size = sizeof(msg->body); 790b9450e43SRui Paulo msg->tag_hdr.val_len = sizeof(msg->body.req); 791b9450e43SRui Paulo msg->body.req.voltage_id = voltage_id; 792b9450e43SRui Paulo msg->body.req.value = (uint32_t)value; 793b9450e43SRui Paulo msg->end_tag = 0; 794b9450e43SRui Paulo 795b9450e43SRui Paulo /* call mailbox property */ 796b9450e43SRui Paulo err = bcm2835_mbox_call_prop(sc); 797b9450e43SRui Paulo if (err) { 798b9450e43SRui Paulo device_printf(sc->dev, "can't set voltage\n"); 799b9450e43SRui Paulo return (MSG_ERROR); 800b9450e43SRui Paulo } 801b9450e43SRui Paulo 802b9450e43SRui Paulo /* result (offset from 1.2V) */ 803b9450e43SRui Paulo value = (int)msg->body.resp.value; 804b9450e43SRui Paulo DPRINTF("value = %d\n", value); 805b9450e43SRui Paulo return (value); 806b9450e43SRui Paulo } 807b9450e43SRui Paulo 808b9450e43SRui Paulo static int 809b9450e43SRui Paulo bcm2835_cpufreq_get_temperature(struct bcm2835_cpufreq_softc *sc) 810b9450e43SRui Paulo { 811b9450e43SRui Paulo struct msg_get_temperature *msg; 812b9450e43SRui Paulo int value; 813b9450e43SRui Paulo int err; 814b9450e43SRui Paulo 815b9450e43SRui Paulo /* 816b9450e43SRui Paulo * Get temperature 817b9450e43SRui Paulo * Tag: 0x00030006 818b9450e43SRui Paulo * Request: 819b9450e43SRui Paulo * Length: 4 820b9450e43SRui Paulo * Value: 821b9450e43SRui Paulo * u32: temperature id 822b9450e43SRui Paulo * Response: 823b9450e43SRui Paulo * Length: 8 824b9450e43SRui Paulo * Value: 825b9450e43SRui Paulo * u32: temperature id 826b9450e43SRui Paulo * u32: value 827b9450e43SRui Paulo */ 828b9450e43SRui Paulo 829b9450e43SRui Paulo /* using DMA buffer for VC */ 830b9450e43SRui Paulo msg = (struct msg_get_temperature *)sc->dma_buf; 831b9450e43SRui Paulo if (sizeof(*msg) > sc->dma_size) { 832b9450e43SRui Paulo device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n", 833b9450e43SRui Paulo sizeof(*msg), sc->dma_size); 834b9450e43SRui Paulo return (MSG_ERROR); 835b9450e43SRui Paulo } 836b9450e43SRui Paulo 837b9450e43SRui Paulo /* setup single tag buffer */ 838b9450e43SRui Paulo memset(msg, 0, sizeof(*msg)); 839b9450e43SRui Paulo msg->hdr.buf_size = sizeof(*msg); 840b9450e43SRui Paulo msg->hdr.code = BCM2835_MBOX_CODE_REQ; 841b9450e43SRui Paulo msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_TEMPERATURE; 842b9450e43SRui Paulo msg->tag_hdr.val_buf_size = sizeof(msg->body); 843b9450e43SRui Paulo msg->tag_hdr.val_len = sizeof(msg->body.req); 844b9450e43SRui Paulo msg->body.req.temperature_id = 0; 845b9450e43SRui Paulo msg->end_tag = 0; 846b9450e43SRui Paulo 847b9450e43SRui Paulo /* call mailbox property */ 848b9450e43SRui Paulo err = bcm2835_mbox_call_prop(sc); 849b9450e43SRui Paulo if (err) { 850b9450e43SRui Paulo device_printf(sc->dev, "can't get temperature\n"); 851b9450e43SRui Paulo return (MSG_ERROR); 852b9450e43SRui Paulo } 853b9450e43SRui Paulo 854b9450e43SRui Paulo /* result (temperature of degree C) */ 855b9450e43SRui Paulo value = (int)msg->body.resp.value; 856b9450e43SRui Paulo DPRINTF("value = %d\n", value); 857b9450e43SRui Paulo return (value); 858b9450e43SRui Paulo } 859b9450e43SRui Paulo 860b9450e43SRui Paulo 861b9450e43SRui Paulo 862b9450e43SRui Paulo static int 863b9450e43SRui Paulo sysctl_bcm2835_cpufreq_arm_freq(SYSCTL_HANDLER_ARGS) 864b9450e43SRui Paulo { 865b9450e43SRui Paulo struct bcm2835_cpufreq_softc *sc = arg1; 866b9450e43SRui Paulo int val; 867b9450e43SRui Paulo int err; 868b9450e43SRui Paulo 869b9450e43SRui Paulo /* get realtime value */ 870b9450e43SRui Paulo VC_LOCK(sc); 871b9450e43SRui Paulo val = bcm2835_cpufreq_get_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_ARM); 872b9450e43SRui Paulo VC_UNLOCK(sc); 873b9450e43SRui Paulo if (val == MSG_ERROR) 874b9450e43SRui Paulo return (EIO); 875b9450e43SRui Paulo 876b9450e43SRui Paulo err = sysctl_handle_int(oidp, &val, 0, req); 877b9450e43SRui Paulo if (err || !req->newptr) /* error || read request */ 878b9450e43SRui Paulo return (err); 879b9450e43SRui Paulo 880b9450e43SRui Paulo /* write request */ 881b9450e43SRui Paulo VC_LOCK(sc); 882b9450e43SRui Paulo err = bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_ARM, 883b9450e43SRui Paulo val); 884b9450e43SRui Paulo VC_UNLOCK(sc); 885b9450e43SRui Paulo if (err == MSG_ERROR) { 886b9450e43SRui Paulo device_printf(sc->dev, "set clock arm_freq error\n"); 887b9450e43SRui Paulo return (EIO); 888b9450e43SRui Paulo } 889b9450e43SRui Paulo DELAY(TRANSITION_LATENCY); 890b9450e43SRui Paulo 891b9450e43SRui Paulo return (0); 892b9450e43SRui Paulo } 893b9450e43SRui Paulo 894b9450e43SRui Paulo static int 895b9450e43SRui Paulo sysctl_bcm2835_cpufreq_core_freq(SYSCTL_HANDLER_ARGS) 896b9450e43SRui Paulo { 897b9450e43SRui Paulo struct bcm2835_cpufreq_softc *sc = arg1; 898b9450e43SRui Paulo int val; 899b9450e43SRui Paulo int err; 900b9450e43SRui Paulo 901b9450e43SRui Paulo /* get realtime value */ 902b9450e43SRui Paulo VC_LOCK(sc); 903b9450e43SRui Paulo val = bcm2835_cpufreq_get_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_CORE); 904b9450e43SRui Paulo VC_UNLOCK(sc); 905b9450e43SRui Paulo if (val == MSG_ERROR) 906b9450e43SRui Paulo return (EIO); 907b9450e43SRui Paulo 908b9450e43SRui Paulo err = sysctl_handle_int(oidp, &val, 0, req); 909b9450e43SRui Paulo if (err || !req->newptr) /* error || read request */ 910b9450e43SRui Paulo return (err); 911b9450e43SRui Paulo 912b9450e43SRui Paulo /* write request */ 913b9450e43SRui Paulo VC_LOCK(sc); 914b9450e43SRui Paulo err = bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_CORE, 915b9450e43SRui Paulo val); 916b9450e43SRui Paulo if (err == MSG_ERROR) { 917b9450e43SRui Paulo VC_UNLOCK(sc); 918b9450e43SRui Paulo device_printf(sc->dev, "set clock core_freq error\n"); 919b9450e43SRui Paulo return (EIO); 920b9450e43SRui Paulo } 921b9450e43SRui Paulo VC_UNLOCK(sc); 922b9450e43SRui Paulo DELAY(TRANSITION_LATENCY); 923b9450e43SRui Paulo 924b9450e43SRui Paulo return (0); 925b9450e43SRui Paulo } 926b9450e43SRui Paulo 927b9450e43SRui Paulo static int 928b9450e43SRui Paulo sysctl_bcm2835_cpufreq_sdram_freq(SYSCTL_HANDLER_ARGS) 929b9450e43SRui Paulo { 930b9450e43SRui Paulo struct bcm2835_cpufreq_softc *sc = arg1; 931b9450e43SRui Paulo int val; 932b9450e43SRui Paulo int err; 933b9450e43SRui Paulo 934b9450e43SRui Paulo /* get realtime value */ 935b9450e43SRui Paulo VC_LOCK(sc); 936b9450e43SRui Paulo val = bcm2835_cpufreq_get_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_SDRAM); 937b9450e43SRui Paulo VC_UNLOCK(sc); 938b9450e43SRui Paulo if (val == MSG_ERROR) 939b9450e43SRui Paulo return (EIO); 940b9450e43SRui Paulo 941b9450e43SRui Paulo err = sysctl_handle_int(oidp, &val, 0, req); 942b9450e43SRui Paulo if (err || !req->newptr) /* error || read request */ 943b9450e43SRui Paulo return (err); 944b9450e43SRui Paulo 945b9450e43SRui Paulo /* write request */ 946b9450e43SRui Paulo VC_LOCK(sc); 947b9450e43SRui Paulo err = bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_SDRAM, 948b9450e43SRui Paulo val); 949b9450e43SRui Paulo VC_UNLOCK(sc); 950b9450e43SRui Paulo if (err == MSG_ERROR) { 951b9450e43SRui Paulo device_printf(sc->dev, "set clock sdram_freq error\n"); 952b9450e43SRui Paulo return (EIO); 953b9450e43SRui Paulo } 954b9450e43SRui Paulo DELAY(TRANSITION_LATENCY); 955b9450e43SRui Paulo 956b9450e43SRui Paulo return (0); 957b9450e43SRui Paulo } 958b9450e43SRui Paulo 959b9450e43SRui Paulo static int 960b9450e43SRui Paulo sysctl_bcm2835_cpufreq_turbo(SYSCTL_HANDLER_ARGS) 961b9450e43SRui Paulo { 962b9450e43SRui Paulo struct bcm2835_cpufreq_softc *sc = arg1; 963b9450e43SRui Paulo int val; 964b9450e43SRui Paulo int err; 965b9450e43SRui Paulo 966b9450e43SRui Paulo /* get realtime value */ 967b9450e43SRui Paulo VC_LOCK(sc); 968b9450e43SRui Paulo val = bcm2835_cpufreq_get_turbo(sc); 969b9450e43SRui Paulo VC_UNLOCK(sc); 970b9450e43SRui Paulo if (val == MSG_ERROR) 971b9450e43SRui Paulo return (EIO); 972b9450e43SRui Paulo 973b9450e43SRui Paulo err = sysctl_handle_int(oidp, &val, 0, req); 974b9450e43SRui Paulo if (err || !req->newptr) /* error || read request */ 975b9450e43SRui Paulo return (err); 976b9450e43SRui Paulo 977b9450e43SRui Paulo /* write request */ 978b9450e43SRui Paulo if (val > 0) 979b9450e43SRui Paulo sc->turbo_mode = BCM2835_MBOX_TURBO_ON; 980b9450e43SRui Paulo else 981b9450e43SRui Paulo sc->turbo_mode = BCM2835_MBOX_TURBO_OFF; 982b9450e43SRui Paulo 983b9450e43SRui Paulo VC_LOCK(sc); 984b9450e43SRui Paulo err = bcm2835_cpufreq_set_turbo(sc, sc->turbo_mode); 985b9450e43SRui Paulo VC_UNLOCK(sc); 986b9450e43SRui Paulo if (err == MSG_ERROR) { 987b9450e43SRui Paulo device_printf(sc->dev, "set turbo error\n"); 988b9450e43SRui Paulo return (EIO); 989b9450e43SRui Paulo } 990b9450e43SRui Paulo DELAY(TRANSITION_LATENCY); 991b9450e43SRui Paulo 992b9450e43SRui Paulo return (0); 993b9450e43SRui Paulo } 994b9450e43SRui Paulo 995b9450e43SRui Paulo static int 996b9450e43SRui Paulo sysctl_bcm2835_cpufreq_voltage_core(SYSCTL_HANDLER_ARGS) 997b9450e43SRui Paulo { 998b9450e43SRui Paulo struct bcm2835_cpufreq_softc *sc = arg1; 999b9450e43SRui Paulo int val; 1000b9450e43SRui Paulo int err; 1001b9450e43SRui Paulo 1002b9450e43SRui Paulo /* get realtime value */ 1003b9450e43SRui Paulo VC_LOCK(sc); 1004b9450e43SRui Paulo val = bcm2835_cpufreq_get_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_CORE); 1005b9450e43SRui Paulo VC_UNLOCK(sc); 1006b9450e43SRui Paulo if (val == MSG_ERROR) 1007b9450e43SRui Paulo return (EIO); 1008b9450e43SRui Paulo 1009b9450e43SRui Paulo err = sysctl_handle_int(oidp, &val, 0, req); 1010b9450e43SRui Paulo if (err || !req->newptr) /* error || read request */ 1011b9450e43SRui Paulo return (err); 1012b9450e43SRui Paulo 1013b9450e43SRui Paulo /* write request */ 1014b9450e43SRui Paulo if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE) 1015b9450e43SRui Paulo return (EINVAL); 1016b9450e43SRui Paulo sc->voltage_core = val; 1017b9450e43SRui Paulo 1018b9450e43SRui Paulo VC_LOCK(sc); 1019b9450e43SRui Paulo err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_CORE, 1020b9450e43SRui Paulo sc->voltage_core); 1021b9450e43SRui Paulo VC_UNLOCK(sc); 1022b9450e43SRui Paulo if (err == MSG_ERROR) { 1023b9450e43SRui Paulo device_printf(sc->dev, "set voltage core error\n"); 1024b9450e43SRui Paulo return (EIO); 1025b9450e43SRui Paulo } 1026b9450e43SRui Paulo DELAY(TRANSITION_LATENCY); 1027b9450e43SRui Paulo 1028b9450e43SRui Paulo return (0); 1029b9450e43SRui Paulo } 1030b9450e43SRui Paulo 1031b9450e43SRui Paulo static int 1032b9450e43SRui Paulo sysctl_bcm2835_cpufreq_voltage_sdram_c(SYSCTL_HANDLER_ARGS) 1033b9450e43SRui Paulo { 1034b9450e43SRui Paulo struct bcm2835_cpufreq_softc *sc = arg1; 1035b9450e43SRui Paulo int val; 1036b9450e43SRui Paulo int err; 1037b9450e43SRui Paulo 1038b9450e43SRui Paulo /* get realtime value */ 1039b9450e43SRui Paulo VC_LOCK(sc); 1040b9450e43SRui Paulo val = bcm2835_cpufreq_get_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_C); 1041b9450e43SRui Paulo VC_UNLOCK(sc); 1042b9450e43SRui Paulo if (val == MSG_ERROR) 1043b9450e43SRui Paulo return (EIO); 1044b9450e43SRui Paulo 1045b9450e43SRui Paulo err = sysctl_handle_int(oidp, &val, 0, req); 1046b9450e43SRui Paulo if (err || !req->newptr) /* error || read request */ 1047b9450e43SRui Paulo return (err); 1048b9450e43SRui Paulo 1049b9450e43SRui Paulo /* write request */ 1050b9450e43SRui Paulo if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE) 1051b9450e43SRui Paulo return (EINVAL); 1052b9450e43SRui Paulo sc->voltage_sdram_c = val; 1053b9450e43SRui Paulo 1054b9450e43SRui Paulo VC_LOCK(sc); 1055b9450e43SRui Paulo err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_C, 1056b9450e43SRui Paulo sc->voltage_sdram_c); 1057b9450e43SRui Paulo VC_UNLOCK(sc); 1058b9450e43SRui Paulo if (err == MSG_ERROR) { 1059b9450e43SRui Paulo device_printf(sc->dev, "set voltage sdram_c error\n"); 1060b9450e43SRui Paulo return (EIO); 1061b9450e43SRui Paulo } 1062b9450e43SRui Paulo DELAY(TRANSITION_LATENCY); 1063b9450e43SRui Paulo 1064b9450e43SRui Paulo return (0); 1065b9450e43SRui Paulo } 1066b9450e43SRui Paulo 1067b9450e43SRui Paulo static int 1068b9450e43SRui Paulo sysctl_bcm2835_cpufreq_voltage_sdram_i(SYSCTL_HANDLER_ARGS) 1069b9450e43SRui Paulo { 1070b9450e43SRui Paulo struct bcm2835_cpufreq_softc *sc = arg1; 1071b9450e43SRui Paulo int val; 1072b9450e43SRui Paulo int err; 1073b9450e43SRui Paulo 1074b9450e43SRui Paulo /* get realtime value */ 1075b9450e43SRui Paulo VC_LOCK(sc); 1076b9450e43SRui Paulo val = bcm2835_cpufreq_get_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_I); 1077b9450e43SRui Paulo VC_UNLOCK(sc); 1078b9450e43SRui Paulo if (val == MSG_ERROR) 1079b9450e43SRui Paulo return (EIO); 1080b9450e43SRui Paulo 1081b9450e43SRui Paulo err = sysctl_handle_int(oidp, &val, 0, req); 1082b9450e43SRui Paulo if (err || !req->newptr) /* error || read request */ 1083b9450e43SRui Paulo return (err); 1084b9450e43SRui Paulo 1085b9450e43SRui Paulo /* write request */ 1086b9450e43SRui Paulo if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE) 1087b9450e43SRui Paulo return (EINVAL); 1088b9450e43SRui Paulo sc->voltage_sdram_i = val; 1089b9450e43SRui Paulo 1090b9450e43SRui Paulo VC_LOCK(sc); 1091b9450e43SRui Paulo err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_I, 1092b9450e43SRui Paulo sc->voltage_sdram_i); 1093b9450e43SRui Paulo VC_UNLOCK(sc); 1094b9450e43SRui Paulo if (err == MSG_ERROR) { 1095b9450e43SRui Paulo device_printf(sc->dev, "set voltage sdram_i error\n"); 1096b9450e43SRui Paulo return (EIO); 1097b9450e43SRui Paulo } 1098b9450e43SRui Paulo DELAY(TRANSITION_LATENCY); 1099b9450e43SRui Paulo 1100b9450e43SRui Paulo return (0); 1101b9450e43SRui Paulo } 1102b9450e43SRui Paulo 1103b9450e43SRui Paulo static int 1104b9450e43SRui Paulo sysctl_bcm2835_cpufreq_voltage_sdram_p(SYSCTL_HANDLER_ARGS) 1105b9450e43SRui Paulo { 1106b9450e43SRui Paulo struct bcm2835_cpufreq_softc *sc = arg1; 1107b9450e43SRui Paulo int val; 1108b9450e43SRui Paulo int err; 1109b9450e43SRui Paulo 1110b9450e43SRui Paulo /* get realtime value */ 1111b9450e43SRui Paulo VC_LOCK(sc); 1112b9450e43SRui Paulo val = bcm2835_cpufreq_get_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_P); 1113b9450e43SRui Paulo VC_UNLOCK(sc); 1114b9450e43SRui Paulo if (val == MSG_ERROR) 1115b9450e43SRui Paulo return (EIO); 1116b9450e43SRui Paulo 1117b9450e43SRui Paulo err = sysctl_handle_int(oidp, &val, 0, req); 1118b9450e43SRui Paulo if (err || !req->newptr) /* error || read request */ 1119b9450e43SRui Paulo return (err); 1120b9450e43SRui Paulo 1121b9450e43SRui Paulo /* write request */ 1122b9450e43SRui Paulo if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE) 1123b9450e43SRui Paulo return (EINVAL); 1124b9450e43SRui Paulo sc->voltage_sdram_p = val; 1125b9450e43SRui Paulo 1126b9450e43SRui Paulo VC_LOCK(sc); 1127b9450e43SRui Paulo err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_P, 1128b9450e43SRui Paulo sc->voltage_sdram_p); 1129b9450e43SRui Paulo VC_UNLOCK(sc); 1130b9450e43SRui Paulo if (err == MSG_ERROR) { 1131b9450e43SRui Paulo device_printf(sc->dev, "set voltage sdram_p error\n"); 1132b9450e43SRui Paulo return (EIO); 1133b9450e43SRui Paulo } 1134b9450e43SRui Paulo DELAY(TRANSITION_LATENCY); 1135b9450e43SRui Paulo 1136b9450e43SRui Paulo return (0); 1137b9450e43SRui Paulo } 1138b9450e43SRui Paulo 1139b9450e43SRui Paulo static int 1140b9450e43SRui Paulo sysctl_bcm2835_cpufreq_voltage_sdram(SYSCTL_HANDLER_ARGS) 1141b9450e43SRui Paulo { 1142b9450e43SRui Paulo struct bcm2835_cpufreq_softc *sc = arg1; 1143b9450e43SRui Paulo int val; 1144b9450e43SRui Paulo int err; 1145b9450e43SRui Paulo 1146b9450e43SRui Paulo /* multiple write only */ 1147b9450e43SRui Paulo if (!req->newptr) 1148b9450e43SRui Paulo return (EINVAL); 1149b9450e43SRui Paulo val = 0; 1150b9450e43SRui Paulo err = sysctl_handle_int(oidp, &val, 0, req); 1151b9450e43SRui Paulo if (err) 1152b9450e43SRui Paulo return (err); 1153b9450e43SRui Paulo 1154b9450e43SRui Paulo /* write request */ 1155b9450e43SRui Paulo if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE) 1156b9450e43SRui Paulo return (EINVAL); 1157b9450e43SRui Paulo sc->voltage_sdram = val; 1158b9450e43SRui Paulo 1159b9450e43SRui Paulo VC_LOCK(sc); 1160b9450e43SRui Paulo err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_C, 1161b9450e43SRui Paulo val); 1162b9450e43SRui Paulo if (err == MSG_ERROR) { 1163b9450e43SRui Paulo VC_UNLOCK(sc); 1164b9450e43SRui Paulo device_printf(sc->dev, "set voltage sdram_c error\n"); 1165b9450e43SRui Paulo return (EIO); 1166b9450e43SRui Paulo } 1167b9450e43SRui Paulo err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_I, 1168b9450e43SRui Paulo val); 1169b9450e43SRui Paulo if (err == MSG_ERROR) { 1170b9450e43SRui Paulo VC_UNLOCK(sc); 1171b9450e43SRui Paulo device_printf(sc->dev, "set voltage sdram_i error\n"); 1172b9450e43SRui Paulo return (EIO); 1173b9450e43SRui Paulo } 1174b9450e43SRui Paulo err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_P, 1175b9450e43SRui Paulo val); 1176b9450e43SRui Paulo if (err == MSG_ERROR) { 1177b9450e43SRui Paulo VC_UNLOCK(sc); 1178b9450e43SRui Paulo device_printf(sc->dev, "set voltage sdram_p error\n"); 1179b9450e43SRui Paulo return (EIO); 1180b9450e43SRui Paulo } 1181b9450e43SRui Paulo VC_UNLOCK(sc); 1182b9450e43SRui Paulo DELAY(TRANSITION_LATENCY); 1183b9450e43SRui Paulo 1184b9450e43SRui Paulo return (0); 1185b9450e43SRui Paulo } 1186b9450e43SRui Paulo 1187b9450e43SRui Paulo static int 1188b9450e43SRui Paulo sysctl_bcm2835_cpufreq_temperature(SYSCTL_HANDLER_ARGS) 1189b9450e43SRui Paulo { 1190b9450e43SRui Paulo struct bcm2835_cpufreq_softc *sc = arg1; 1191b9450e43SRui Paulo int val; 1192b9450e43SRui Paulo int err; 1193b9450e43SRui Paulo 1194b9450e43SRui Paulo /* get realtime value */ 1195b9450e43SRui Paulo VC_LOCK(sc); 1196b9450e43SRui Paulo val = bcm2835_cpufreq_get_temperature(sc); 1197b9450e43SRui Paulo VC_UNLOCK(sc); 1198b9450e43SRui Paulo if (val == MSG_ERROR) 1199b9450e43SRui Paulo return (EIO); 1200b9450e43SRui Paulo 1201b9450e43SRui Paulo err = sysctl_handle_int(oidp, &val, 0, req); 1202b9450e43SRui Paulo if (err || !req->newptr) /* error || read request */ 1203b9450e43SRui Paulo return (err); 1204b9450e43SRui Paulo 1205b9450e43SRui Paulo /* write request */ 1206b9450e43SRui Paulo return (EINVAL); 1207b9450e43SRui Paulo } 1208b9450e43SRui Paulo 1209b9450e43SRui Paulo static int 1210b9450e43SRui Paulo sysctl_bcm2835_devcpu_temperature(SYSCTL_HANDLER_ARGS) 1211b9450e43SRui Paulo { 1212b9450e43SRui Paulo struct bcm2835_cpufreq_softc *sc = arg1; 1213b9450e43SRui Paulo int val; 1214b9450e43SRui Paulo int err; 1215b9450e43SRui Paulo 1216b9450e43SRui Paulo /* get realtime value */ 1217b9450e43SRui Paulo VC_LOCK(sc); 1218b9450e43SRui Paulo val = bcm2835_cpufreq_get_temperature(sc); 1219b9450e43SRui Paulo VC_UNLOCK(sc); 1220b9450e43SRui Paulo if (val == MSG_ERROR) 1221b9450e43SRui Paulo return (EIO); 1222b9450e43SRui Paulo 1223b9450e43SRui Paulo /* 1/1000 celsius (raw) to 1/10 kelvin */ 1224e4b6eaf7SLuiz Otavio O Souza val = val / 100 + TZ_ZEROC; 1225b9450e43SRui Paulo 1226b9450e43SRui Paulo err = sysctl_handle_int(oidp, &val, 0, req); 1227b9450e43SRui Paulo if (err || !req->newptr) /* error || read request */ 1228b9450e43SRui Paulo return (err); 1229b9450e43SRui Paulo 1230b9450e43SRui Paulo /* write request */ 1231b9450e43SRui Paulo return (EINVAL); 1232b9450e43SRui Paulo } 1233b9450e43SRui Paulo 1234b9450e43SRui Paulo 1235b9450e43SRui Paulo static void 1236b9450e43SRui Paulo bcm2835_cpufreq_init(void *arg) 1237b9450e43SRui Paulo { 1238b9450e43SRui Paulo struct bcm2835_cpufreq_softc *sc = arg; 1239b9450e43SRui Paulo struct sysctl_ctx_list *ctx; 1240b9450e43SRui Paulo device_t cpu; 1241b9450e43SRui Paulo int arm_freq, core_freq, sdram_freq; 1242b9450e43SRui Paulo int arm_max_freq, arm_min_freq, core_max_freq, core_min_freq; 1243b9450e43SRui Paulo int sdram_max_freq, sdram_min_freq; 1244b9450e43SRui Paulo int voltage_core, voltage_sdram_c, voltage_sdram_i, voltage_sdram_p; 1245b9450e43SRui Paulo int max_voltage_core, min_voltage_core; 1246b9450e43SRui Paulo int max_voltage_sdram_c, min_voltage_sdram_c; 1247b9450e43SRui Paulo int max_voltage_sdram_i, min_voltage_sdram_i; 1248b9450e43SRui Paulo int max_voltage_sdram_p, min_voltage_sdram_p; 1249b9450e43SRui Paulo int turbo, temperature; 1250b9450e43SRui Paulo 1251b9450e43SRui Paulo VC_LOCK(sc); 1252b9450e43SRui Paulo 1253b9450e43SRui Paulo /* current clock */ 1254b9450e43SRui Paulo arm_freq = bcm2835_cpufreq_get_clock_rate(sc, 1255b9450e43SRui Paulo BCM2835_MBOX_CLOCK_ID_ARM); 1256b9450e43SRui Paulo core_freq = bcm2835_cpufreq_get_clock_rate(sc, 1257b9450e43SRui Paulo BCM2835_MBOX_CLOCK_ID_CORE); 1258b9450e43SRui Paulo sdram_freq = bcm2835_cpufreq_get_clock_rate(sc, 1259b9450e43SRui Paulo BCM2835_MBOX_CLOCK_ID_SDRAM); 1260b9450e43SRui Paulo 1261b9450e43SRui Paulo /* max/min clock */ 1262b9450e43SRui Paulo arm_max_freq = bcm2835_cpufreq_get_max_clock_rate(sc, 1263b9450e43SRui Paulo BCM2835_MBOX_CLOCK_ID_ARM); 1264b9450e43SRui Paulo arm_min_freq = bcm2835_cpufreq_get_min_clock_rate(sc, 1265b9450e43SRui Paulo BCM2835_MBOX_CLOCK_ID_ARM); 1266b9450e43SRui Paulo core_max_freq = bcm2835_cpufreq_get_max_clock_rate(sc, 1267b9450e43SRui Paulo BCM2835_MBOX_CLOCK_ID_CORE); 1268b9450e43SRui Paulo core_min_freq = bcm2835_cpufreq_get_min_clock_rate(sc, 1269b9450e43SRui Paulo BCM2835_MBOX_CLOCK_ID_CORE); 1270b9450e43SRui Paulo sdram_max_freq = bcm2835_cpufreq_get_max_clock_rate(sc, 1271b9450e43SRui Paulo BCM2835_MBOX_CLOCK_ID_SDRAM); 1272b9450e43SRui Paulo sdram_min_freq = bcm2835_cpufreq_get_min_clock_rate(sc, 1273b9450e43SRui Paulo BCM2835_MBOX_CLOCK_ID_SDRAM); 1274b9450e43SRui Paulo 1275b9450e43SRui Paulo /* turbo mode */ 1276b9450e43SRui Paulo turbo = bcm2835_cpufreq_get_turbo(sc); 1277b9450e43SRui Paulo if (turbo > 0) 1278b9450e43SRui Paulo sc->turbo_mode = BCM2835_MBOX_TURBO_ON; 1279b9450e43SRui Paulo else 1280b9450e43SRui Paulo sc->turbo_mode = BCM2835_MBOX_TURBO_OFF; 1281b9450e43SRui Paulo 1282b9450e43SRui Paulo /* voltage */ 1283b9450e43SRui Paulo voltage_core = bcm2835_cpufreq_get_voltage(sc, 1284b9450e43SRui Paulo BCM2835_MBOX_VOLTAGE_ID_CORE); 1285b9450e43SRui Paulo voltage_sdram_c = bcm2835_cpufreq_get_voltage(sc, 1286b9450e43SRui Paulo BCM2835_MBOX_VOLTAGE_ID_SDRAM_C); 1287b9450e43SRui Paulo voltage_sdram_i = bcm2835_cpufreq_get_voltage(sc, 1288b9450e43SRui Paulo BCM2835_MBOX_VOLTAGE_ID_SDRAM_I); 1289b9450e43SRui Paulo voltage_sdram_p = bcm2835_cpufreq_get_voltage(sc, 1290b9450e43SRui Paulo BCM2835_MBOX_VOLTAGE_ID_SDRAM_P); 1291b9450e43SRui Paulo 1292b9450e43SRui Paulo /* current values (offset from 1.2V) */ 1293b9450e43SRui Paulo sc->voltage_core = voltage_core; 1294b9450e43SRui Paulo sc->voltage_sdram = voltage_sdram_c; 1295b9450e43SRui Paulo sc->voltage_sdram_c = voltage_sdram_c; 1296b9450e43SRui Paulo sc->voltage_sdram_i = voltage_sdram_i; 1297b9450e43SRui Paulo sc->voltage_sdram_p = voltage_sdram_p; 1298b9450e43SRui Paulo 1299b9450e43SRui Paulo /* max/min voltage */ 1300b9450e43SRui Paulo max_voltage_core = bcm2835_cpufreq_get_max_voltage(sc, 1301b9450e43SRui Paulo BCM2835_MBOX_VOLTAGE_ID_CORE); 1302b9450e43SRui Paulo min_voltage_core = bcm2835_cpufreq_get_min_voltage(sc, 1303b9450e43SRui Paulo BCM2835_MBOX_VOLTAGE_ID_CORE); 1304b9450e43SRui Paulo max_voltage_sdram_c = bcm2835_cpufreq_get_max_voltage(sc, 1305b9450e43SRui Paulo BCM2835_MBOX_VOLTAGE_ID_SDRAM_C); 1306b9450e43SRui Paulo max_voltage_sdram_i = bcm2835_cpufreq_get_max_voltage(sc, 1307b9450e43SRui Paulo BCM2835_MBOX_VOLTAGE_ID_SDRAM_I); 1308b9450e43SRui Paulo max_voltage_sdram_p = bcm2835_cpufreq_get_max_voltage(sc, 1309b9450e43SRui Paulo BCM2835_MBOX_VOLTAGE_ID_SDRAM_P); 1310b9450e43SRui Paulo min_voltage_sdram_c = bcm2835_cpufreq_get_min_voltage(sc, 1311b9450e43SRui Paulo BCM2835_MBOX_VOLTAGE_ID_SDRAM_C); 1312b9450e43SRui Paulo min_voltage_sdram_i = bcm2835_cpufreq_get_min_voltage(sc, 1313b9450e43SRui Paulo BCM2835_MBOX_VOLTAGE_ID_SDRAM_I); 1314b9450e43SRui Paulo min_voltage_sdram_p = bcm2835_cpufreq_get_min_voltage(sc, 1315b9450e43SRui Paulo BCM2835_MBOX_VOLTAGE_ID_SDRAM_P); 1316b9450e43SRui Paulo 1317b9450e43SRui Paulo /* temperature */ 1318b9450e43SRui Paulo temperature = bcm2835_cpufreq_get_temperature(sc); 1319b9450e43SRui Paulo 1320b9450e43SRui Paulo /* show result */ 1321b9450e43SRui Paulo if (cpufreq_verbose || bootverbose) { 1322b9450e43SRui Paulo device_printf(sc->dev, "Boot settings:\n"); 1323b9450e43SRui Paulo device_printf(sc->dev, 1324b9450e43SRui Paulo "current ARM %dMHz, Core %dMHz, SDRAM %dMHz, Turbo %s\n", 1325b9450e43SRui Paulo HZ2MHZ(arm_freq), HZ2MHZ(core_freq), HZ2MHZ(sdram_freq), 1326b9450e43SRui Paulo (sc->turbo_mode == BCM2835_MBOX_TURBO_ON) ? "ON" : "OFF"); 1327b9450e43SRui Paulo 1328b9450e43SRui Paulo device_printf(sc->dev, 1329b9450e43SRui Paulo "max/min ARM %d/%dMHz, Core %d/%dMHz, SDRAM %d/%dMHz\n", 1330b9450e43SRui Paulo HZ2MHZ(arm_max_freq), HZ2MHZ(arm_min_freq), 1331b9450e43SRui Paulo HZ2MHZ(core_max_freq), HZ2MHZ(core_min_freq), 1332b9450e43SRui Paulo HZ2MHZ(sdram_max_freq), HZ2MHZ(sdram_min_freq)); 1333b9450e43SRui Paulo 1334b9450e43SRui Paulo device_printf(sc->dev, 1335b9450e43SRui Paulo "current Core %dmV, SDRAM_C %dmV, SDRAM_I %dmV, " 1336b9450e43SRui Paulo "SDRAM_P %dmV\n", 1337b9450e43SRui Paulo OFFSET2MVOLT(voltage_core), OFFSET2MVOLT(voltage_sdram_c), 1338b9450e43SRui Paulo OFFSET2MVOLT(voltage_sdram_i), 1339b9450e43SRui Paulo OFFSET2MVOLT(voltage_sdram_p)); 1340b9450e43SRui Paulo 1341b9450e43SRui Paulo device_printf(sc->dev, 1342b9450e43SRui Paulo "max/min Core %d/%dmV, SDRAM_C %d/%dmV, SDRAM_I %d/%dmV, " 1343b9450e43SRui Paulo "SDRAM_P %d/%dmV\n", 1344b9450e43SRui Paulo OFFSET2MVOLT(max_voltage_core), 1345b9450e43SRui Paulo OFFSET2MVOLT(min_voltage_core), 1346b9450e43SRui Paulo OFFSET2MVOLT(max_voltage_sdram_c), 1347b9450e43SRui Paulo OFFSET2MVOLT(min_voltage_sdram_c), 1348b9450e43SRui Paulo OFFSET2MVOLT(max_voltage_sdram_i), 1349b9450e43SRui Paulo OFFSET2MVOLT(min_voltage_sdram_i), 1350b9450e43SRui Paulo OFFSET2MVOLT(max_voltage_sdram_p), 1351b9450e43SRui Paulo OFFSET2MVOLT(min_voltage_sdram_p)); 1352b9450e43SRui Paulo 1353b9450e43SRui Paulo device_printf(sc->dev, 1354b9450e43SRui Paulo "Temperature %d.%dC\n", (temperature / 1000), 1355b9450e43SRui Paulo (temperature % 1000) / 100); 1356b9450e43SRui Paulo } else { /* !cpufreq_verbose && !bootverbose */ 1357b9450e43SRui Paulo device_printf(sc->dev, 1358b9450e43SRui Paulo "ARM %dMHz, Core %dMHz, SDRAM %dMHz, Turbo %s\n", 1359b9450e43SRui Paulo HZ2MHZ(arm_freq), HZ2MHZ(core_freq), HZ2MHZ(sdram_freq), 1360b9450e43SRui Paulo (sc->turbo_mode == BCM2835_MBOX_TURBO_ON) ? "ON" : "OFF"); 1361b9450e43SRui Paulo } 1362b9450e43SRui Paulo 1363b9450e43SRui Paulo /* keep in softc (MHz/mV) */ 1364b9450e43SRui Paulo sc->arm_max_freq = HZ2MHZ(arm_max_freq); 1365b9450e43SRui Paulo sc->arm_min_freq = HZ2MHZ(arm_min_freq); 1366b9450e43SRui Paulo sc->core_max_freq = HZ2MHZ(core_max_freq); 1367b9450e43SRui Paulo sc->core_min_freq = HZ2MHZ(core_min_freq); 1368b9450e43SRui Paulo sc->sdram_max_freq = HZ2MHZ(sdram_max_freq); 1369b9450e43SRui Paulo sc->sdram_min_freq = HZ2MHZ(sdram_min_freq); 1370b9450e43SRui Paulo sc->max_voltage_core = OFFSET2MVOLT(max_voltage_core); 1371b9450e43SRui Paulo sc->min_voltage_core = OFFSET2MVOLT(min_voltage_core); 1372b9450e43SRui Paulo 1373b9450e43SRui Paulo /* if turbo is on, set to max values */ 1374b9450e43SRui Paulo if (sc->turbo_mode == BCM2835_MBOX_TURBO_ON) { 1375b9450e43SRui Paulo bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_ARM, 1376b9450e43SRui Paulo arm_max_freq); 1377b9450e43SRui Paulo DELAY(TRANSITION_LATENCY); 1378b9450e43SRui Paulo bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_CORE, 1379b9450e43SRui Paulo core_max_freq); 1380b9450e43SRui Paulo DELAY(TRANSITION_LATENCY); 1381b9450e43SRui Paulo bcm2835_cpufreq_set_clock_rate(sc, 1382b9450e43SRui Paulo BCM2835_MBOX_CLOCK_ID_SDRAM, sdram_max_freq); 1383b9450e43SRui Paulo DELAY(TRANSITION_LATENCY); 1384b9450e43SRui Paulo } else { 1385b9450e43SRui Paulo bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_ARM, 1386b9450e43SRui Paulo arm_min_freq); 1387b9450e43SRui Paulo DELAY(TRANSITION_LATENCY); 1388b9450e43SRui Paulo bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_CORE, 1389b9450e43SRui Paulo core_min_freq); 1390b9450e43SRui Paulo DELAY(TRANSITION_LATENCY); 1391b9450e43SRui Paulo bcm2835_cpufreq_set_clock_rate(sc, 1392b9450e43SRui Paulo BCM2835_MBOX_CLOCK_ID_SDRAM, sdram_min_freq); 1393b9450e43SRui Paulo DELAY(TRANSITION_LATENCY); 1394b9450e43SRui Paulo } 1395b9450e43SRui Paulo 1396b9450e43SRui Paulo VC_UNLOCK(sc); 1397b9450e43SRui Paulo 1398b9450e43SRui Paulo /* add human readable temperature to dev.cpu node */ 1399b9450e43SRui Paulo cpu = device_get_parent(sc->dev); 1400b9450e43SRui Paulo if (cpu != NULL) { 1401b9450e43SRui Paulo ctx = device_get_sysctl_ctx(cpu); 1402b9450e43SRui Paulo SYSCTL_ADD_PROC(ctx, 1403b9450e43SRui Paulo SYSCTL_CHILDREN(device_get_sysctl_tree(cpu)), OID_AUTO, 1404b9450e43SRui Paulo "temperature", CTLTYPE_INT | CTLFLAG_RD, sc, 0, 1405b9450e43SRui Paulo sysctl_bcm2835_devcpu_temperature, "IK", 1406b9450e43SRui Paulo "Current SoC temperature"); 1407b9450e43SRui Paulo } 1408b9450e43SRui Paulo 1409b9450e43SRui Paulo /* release this hook (continue boot) */ 1410b9450e43SRui Paulo config_intrhook_disestablish(&sc->init_hook); 1411b9450e43SRui Paulo } 1412b9450e43SRui Paulo 1413b9450e43SRui Paulo static void 1414b9450e43SRui Paulo bcm2835_cpufreq_identify(driver_t *driver, device_t parent) 1415b9450e43SRui Paulo { 1416b9450e43SRui Paulo 1417b9450e43SRui Paulo DPRINTF("driver=%p, parent=%p\n", driver, parent); 1418b9450e43SRui Paulo if (device_find_child(parent, "bcm2835_cpufreq", -1) != NULL) 1419b9450e43SRui Paulo return; 1420b9450e43SRui Paulo if (BUS_ADD_CHILD(parent, 0, "bcm2835_cpufreq", -1) == NULL) 1421b9450e43SRui Paulo device_printf(parent, "add child failed\n"); 1422b9450e43SRui Paulo } 1423b9450e43SRui Paulo 1424b9450e43SRui Paulo static int 1425b9450e43SRui Paulo bcm2835_cpufreq_probe(device_t dev) 1426b9450e43SRui Paulo { 1427b9450e43SRui Paulo 1428*962940ceSLuiz Otavio O Souza if (device_get_unit(dev) != 0) 1429*962940ceSLuiz Otavio O Souza return (ENXIO); 1430b9450e43SRui Paulo device_set_desc(dev, "CPU Frequency Control"); 1431*962940ceSLuiz Otavio O Souza 1432b9450e43SRui Paulo return (0); 1433b9450e43SRui Paulo } 1434b9450e43SRui Paulo 1435b9450e43SRui Paulo static void 1436b9450e43SRui Paulo bcm2835_cpufreq_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) 1437b9450e43SRui Paulo { 1438b9450e43SRui Paulo bus_addr_t *addr; 1439b9450e43SRui Paulo 1440b9450e43SRui Paulo if (err) 1441b9450e43SRui Paulo return; 1442b9450e43SRui Paulo addr = (bus_addr_t *)arg; 1443b9450e43SRui Paulo *addr = PHYS_TO_VCBUS(segs[0].ds_addr); 1444b9450e43SRui Paulo } 1445b9450e43SRui Paulo 1446b9450e43SRui Paulo static int 1447b9450e43SRui Paulo bcm2835_cpufreq_attach(device_t dev) 1448b9450e43SRui Paulo { 1449b9450e43SRui Paulo struct bcm2835_cpufreq_softc *sc; 1450b9450e43SRui Paulo struct sysctl_oid *oid; 1451b9450e43SRui Paulo int err; 1452b9450e43SRui Paulo 1453b9450e43SRui Paulo /* set self dev */ 1454b9450e43SRui Paulo sc = device_get_softc(dev); 1455b9450e43SRui Paulo sc->dev = dev; 1456b9450e43SRui Paulo 1457b9450e43SRui Paulo /* initial values */ 1458b9450e43SRui Paulo sc->arm_max_freq = -1; 1459b9450e43SRui Paulo sc->arm_min_freq = -1; 1460b9450e43SRui Paulo sc->core_max_freq = -1; 1461b9450e43SRui Paulo sc->core_min_freq = -1; 1462b9450e43SRui Paulo sc->sdram_max_freq = -1; 1463b9450e43SRui Paulo sc->sdram_min_freq = -1; 1464b9450e43SRui Paulo sc->max_voltage_core = 0; 1465b9450e43SRui Paulo sc->min_voltage_core = 0; 1466b9450e43SRui Paulo 1467b9450e43SRui Paulo /* create VC mbox buffer */ 1468b9450e43SRui Paulo sc->dma_size = PAGE_SIZE; 1469b9450e43SRui Paulo err = bus_dma_tag_create( 1470b9450e43SRui Paulo bus_get_dma_tag(sc->dev), 1471b9450e43SRui Paulo PAGE_SIZE, 0, /* alignment, boundary */ 1472b9450e43SRui Paulo BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 1473b9450e43SRui Paulo BUS_SPACE_MAXADDR, /* highaddr */ 1474b9450e43SRui Paulo NULL, NULL, /* filter, filterarg */ 1475b9450e43SRui Paulo sc->dma_size, 1, /* maxsize, nsegments */ 1476b9450e43SRui Paulo sc->dma_size, 0, /* maxsegsize, flags */ 1477b9450e43SRui Paulo NULL, NULL, /* lockfunc, lockarg */ 1478b9450e43SRui Paulo &sc->dma_tag); 1479b9450e43SRui Paulo if (err) { 1480b9450e43SRui Paulo device_printf(dev, "can't create DMA tag\n"); 1481b9450e43SRui Paulo return (ENXIO); 1482b9450e43SRui Paulo } 1483b9450e43SRui Paulo 1484b9450e43SRui Paulo err = bus_dmamem_alloc(sc->dma_tag, (void **)&sc->dma_buf, 0, 1485b9450e43SRui Paulo &sc->dma_map); 1486b9450e43SRui Paulo if (err) { 1487b9450e43SRui Paulo bus_dma_tag_destroy(sc->dma_tag); 1488b9450e43SRui Paulo device_printf(dev, "can't allocate dmamem\n"); 1489b9450e43SRui Paulo return (ENXIO); 1490b9450e43SRui Paulo } 1491b9450e43SRui Paulo 1492b9450e43SRui Paulo err = bus_dmamap_load(sc->dma_tag, sc->dma_map, sc->dma_buf, 1493b9450e43SRui Paulo sc->dma_size, bcm2835_cpufreq_cb, &sc->dma_phys, 0); 1494b9450e43SRui Paulo if (err) { 1495b9450e43SRui Paulo bus_dmamem_free(sc->dma_tag, sc->dma_buf, sc->dma_map); 1496b9450e43SRui Paulo bus_dma_tag_destroy(sc->dma_tag); 1497b9450e43SRui Paulo device_printf(dev, "can't load DMA map\n"); 1498b9450e43SRui Paulo return (ENXIO); 1499b9450e43SRui Paulo } 1500b9450e43SRui Paulo /* OK, ready to use VC buffer */ 1501b9450e43SRui Paulo 1502b9450e43SRui Paulo /* setup sysctl at first device */ 1503b9450e43SRui Paulo if (device_get_unit(dev) == 0) { 1504b9450e43SRui Paulo sysctl_ctx_init(&bcm2835_sysctl_ctx); 1505b9450e43SRui Paulo /* create node for hw.cpufreq */ 1506b9450e43SRui Paulo oid = SYSCTL_ADD_NODE(&bcm2835_sysctl_ctx, 1507b9450e43SRui Paulo SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, "cpufreq", 1508b9450e43SRui Paulo CTLFLAG_RD, NULL, ""); 1509b9450e43SRui Paulo 1510b9450e43SRui Paulo /* Frequency (Hz) */ 1511b9450e43SRui Paulo SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid), 1512b9450e43SRui Paulo OID_AUTO, "arm_freq", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 1513b9450e43SRui Paulo sysctl_bcm2835_cpufreq_arm_freq, "IU", 1514b9450e43SRui Paulo "ARM frequency (Hz)"); 1515b9450e43SRui Paulo SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid), 1516b9450e43SRui Paulo OID_AUTO, "core_freq", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 1517b9450e43SRui Paulo sysctl_bcm2835_cpufreq_core_freq, "IU", 1518b9450e43SRui Paulo "Core frequency (Hz)"); 1519b9450e43SRui Paulo SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid), 1520b9450e43SRui Paulo OID_AUTO, "sdram_freq", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 1521b9450e43SRui Paulo sysctl_bcm2835_cpufreq_sdram_freq, "IU", 1522b9450e43SRui Paulo "SDRAM frequency (Hz)"); 1523b9450e43SRui Paulo 1524b9450e43SRui Paulo /* Turbo state */ 1525b9450e43SRui Paulo SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid), 1526b9450e43SRui Paulo OID_AUTO, "turbo", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 1527b9450e43SRui Paulo sysctl_bcm2835_cpufreq_turbo, "IU", 1528b9450e43SRui Paulo "Disables dynamic clocking"); 1529b9450e43SRui Paulo 1530b9450e43SRui Paulo /* Voltage (offset from 1.2V in units of 0.025V) */ 1531b9450e43SRui Paulo SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid), 1532b9450e43SRui Paulo OID_AUTO, "voltage_core", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 1533b9450e43SRui Paulo sysctl_bcm2835_cpufreq_voltage_core, "I", 1534b9450e43SRui Paulo "ARM/GPU core voltage" 1535b9450e43SRui Paulo "(offset from 1.2V in units of 0.025V)"); 1536b9450e43SRui Paulo SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid), 1537b9450e43SRui Paulo OID_AUTO, "voltage_sdram", CTLTYPE_INT | CTLFLAG_WR, sc, 1538b9450e43SRui Paulo 0, sysctl_bcm2835_cpufreq_voltage_sdram, "I", 1539b9450e43SRui Paulo "SDRAM voltage (offset from 1.2V in units of 0.025V)"); 1540b9450e43SRui Paulo 1541b9450e43SRui Paulo /* Voltage individual SDRAM */ 1542b9450e43SRui Paulo SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid), 1543b9450e43SRui Paulo OID_AUTO, "voltage_sdram_c", CTLTYPE_INT | CTLFLAG_RW, sc, 1544b9450e43SRui Paulo 0, sysctl_bcm2835_cpufreq_voltage_sdram_c, "I", 1545b9450e43SRui Paulo "SDRAM controller voltage" 1546b9450e43SRui Paulo "(offset from 1.2V in units of 0.025V)"); 1547b9450e43SRui Paulo SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid), 1548b9450e43SRui Paulo OID_AUTO, "voltage_sdram_i", CTLTYPE_INT | CTLFLAG_RW, sc, 1549b9450e43SRui Paulo 0, sysctl_bcm2835_cpufreq_voltage_sdram_i, "I", 1550b9450e43SRui Paulo "SDRAM I/O voltage (offset from 1.2V in units of 0.025V)"); 1551b9450e43SRui Paulo SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid), 1552b9450e43SRui Paulo OID_AUTO, "voltage_sdram_p", CTLTYPE_INT | CTLFLAG_RW, sc, 1553b9450e43SRui Paulo 0, sysctl_bcm2835_cpufreq_voltage_sdram_p, "I", 1554b9450e43SRui Paulo "SDRAM phy voltage (offset from 1.2V in units of 0.025V)"); 1555b9450e43SRui Paulo 1556b9450e43SRui Paulo /* Temperature */ 1557b9450e43SRui Paulo SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid), 1558b9450e43SRui Paulo OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD, sc, 0, 1559b9450e43SRui Paulo sysctl_bcm2835_cpufreq_temperature, "I", 1560b9450e43SRui Paulo "SoC temperature (thousandths of a degree C)"); 1561b9450e43SRui Paulo } 1562b9450e43SRui Paulo 1563b9450e43SRui Paulo /* ARM->VC lock */ 1564b9450e43SRui Paulo sema_init(&vc_sema, 1, "vcsema"); 1565b9450e43SRui Paulo 1566b9450e43SRui Paulo /* register callback for using mbox when interrupts are enabled */ 1567b9450e43SRui Paulo sc->init_hook.ich_func = bcm2835_cpufreq_init; 1568b9450e43SRui Paulo sc->init_hook.ich_arg = sc; 1569b9450e43SRui Paulo 1570b9450e43SRui Paulo if (config_intrhook_establish(&sc->init_hook) != 0) { 1571b9450e43SRui Paulo bus_dmamap_unload(sc->dma_tag, sc->dma_map); 1572b9450e43SRui Paulo bus_dmamem_free(sc->dma_tag, sc->dma_buf, sc->dma_map); 1573b9450e43SRui Paulo bus_dma_tag_destroy(sc->dma_tag); 1574b9450e43SRui Paulo device_printf(dev, "config_intrhook_establish failed\n"); 1575b9450e43SRui Paulo return (ENOMEM); 1576b9450e43SRui Paulo } 1577b9450e43SRui Paulo 1578b9450e43SRui Paulo /* this device is controlled by cpufreq(4) */ 1579b9450e43SRui Paulo cpufreq_register(dev); 1580b9450e43SRui Paulo 1581b9450e43SRui Paulo return (0); 1582b9450e43SRui Paulo } 1583b9450e43SRui Paulo 1584b9450e43SRui Paulo static int 1585b9450e43SRui Paulo bcm2835_cpufreq_detach(device_t dev) 1586b9450e43SRui Paulo { 1587b9450e43SRui Paulo struct bcm2835_cpufreq_softc *sc; 1588b9450e43SRui Paulo 1589b9450e43SRui Paulo sc = device_get_softc(dev); 1590b9450e43SRui Paulo 1591b9450e43SRui Paulo sema_destroy(&vc_sema); 1592b9450e43SRui Paulo 1593b9450e43SRui Paulo if (sc->dma_phys != 0) 1594b9450e43SRui Paulo bus_dmamap_unload(sc->dma_tag, sc->dma_map); 1595b9450e43SRui Paulo if (sc->dma_buf != NULL) 1596b9450e43SRui Paulo bus_dmamem_free(sc->dma_tag, sc->dma_buf, sc->dma_map); 1597b9450e43SRui Paulo if (sc->dma_tag != NULL) 1598b9450e43SRui Paulo bus_dma_tag_destroy(sc->dma_tag); 1599b9450e43SRui Paulo 1600b9450e43SRui Paulo return (cpufreq_unregister(dev)); 1601b9450e43SRui Paulo } 1602b9450e43SRui Paulo 1603b9450e43SRui Paulo static int 1604b9450e43SRui Paulo bcm2835_cpufreq_set(device_t dev, const struct cf_setting *cf) 1605b9450e43SRui Paulo { 1606b9450e43SRui Paulo struct bcm2835_cpufreq_softc *sc; 1607b9450e43SRui Paulo uint32_t rate_hz, rem; 1608b9450e43SRui Paulo int cur_freq, resp_freq, arm_freq, min_freq, core_freq; 1609b9450e43SRui Paulo 1610b9450e43SRui Paulo if (cf == NULL || cf->freq < 0) 1611b9450e43SRui Paulo return (EINVAL); 1612b9450e43SRui Paulo 1613b9450e43SRui Paulo sc = device_get_softc(dev); 1614b9450e43SRui Paulo 1615b9450e43SRui Paulo /* setting clock (Hz) */ 1616b9450e43SRui Paulo rate_hz = (uint32_t)MHZ2HZ(cf->freq); 1617b9450e43SRui Paulo rem = rate_hz % HZSTEP; 1618b9450e43SRui Paulo rate_hz -= rem; 1619b9450e43SRui Paulo if (rate_hz == 0) 1620b9450e43SRui Paulo return (EINVAL); 1621b9450e43SRui Paulo 1622b9450e43SRui Paulo /* adjust min freq */ 1623b9450e43SRui Paulo min_freq = sc->arm_min_freq; 1624b9450e43SRui Paulo if (sc->turbo_mode != BCM2835_MBOX_TURBO_ON) 1625b9450e43SRui Paulo if (min_freq > cpufreq_lowest_freq) 1626b9450e43SRui Paulo min_freq = cpufreq_lowest_freq; 1627b9450e43SRui Paulo 1628b9450e43SRui Paulo if (rate_hz < MHZ2HZ(min_freq) || rate_hz > MHZ2HZ(sc->arm_max_freq)) 1629b9450e43SRui Paulo return (EINVAL); 1630b9450e43SRui Paulo 1631b9450e43SRui Paulo /* set new value and verify it */ 1632b9450e43SRui Paulo VC_LOCK(sc); 1633b9450e43SRui Paulo cur_freq = bcm2835_cpufreq_get_clock_rate(sc, 1634b9450e43SRui Paulo BCM2835_MBOX_CLOCK_ID_ARM); 1635b9450e43SRui Paulo resp_freq = bcm2835_cpufreq_set_clock_rate(sc, 1636b9450e43SRui Paulo BCM2835_MBOX_CLOCK_ID_ARM, rate_hz); 1637b9450e43SRui Paulo DELAY(TRANSITION_LATENCY); 1638b9450e43SRui Paulo arm_freq = bcm2835_cpufreq_get_clock_rate(sc, 1639b9450e43SRui Paulo BCM2835_MBOX_CLOCK_ID_ARM); 1640b9450e43SRui Paulo 1641b9450e43SRui Paulo /* 1642b9450e43SRui Paulo * if non-turbo and lower than or equal min_freq, 1643b9450e43SRui Paulo * clock down core and sdram to default first. 1644b9450e43SRui Paulo */ 1645b9450e43SRui Paulo if (sc->turbo_mode != BCM2835_MBOX_TURBO_ON) { 1646b9450e43SRui Paulo core_freq = bcm2835_cpufreq_get_clock_rate(sc, 1647b9450e43SRui Paulo BCM2835_MBOX_CLOCK_ID_CORE); 1648b9450e43SRui Paulo if (rate_hz > MHZ2HZ(sc->arm_min_freq)) { 1649b9450e43SRui Paulo bcm2835_cpufreq_set_clock_rate(sc, 1650b9450e43SRui Paulo BCM2835_MBOX_CLOCK_ID_CORE, 1651b9450e43SRui Paulo MHZ2HZ(sc->core_max_freq)); 1652b9450e43SRui Paulo DELAY(TRANSITION_LATENCY); 1653b9450e43SRui Paulo bcm2835_cpufreq_set_clock_rate(sc, 1654b9450e43SRui Paulo BCM2835_MBOX_CLOCK_ID_SDRAM, 1655b9450e43SRui Paulo MHZ2HZ(sc->sdram_max_freq)); 1656b9450e43SRui Paulo DELAY(TRANSITION_LATENCY); 1657b9450e43SRui Paulo } else { 1658b9450e43SRui Paulo if (sc->core_min_freq < DEFAULT_CORE_FREQUENCY && 1659b9450e43SRui Paulo core_freq > DEFAULT_CORE_FREQUENCY) { 1660b9450e43SRui Paulo /* first, down to 250, then down to min */ 1661b9450e43SRui Paulo DELAY(TRANSITION_LATENCY); 1662b9450e43SRui Paulo bcm2835_cpufreq_set_clock_rate(sc, 1663b9450e43SRui Paulo BCM2835_MBOX_CLOCK_ID_CORE, 1664b9450e43SRui Paulo MHZ2HZ(DEFAULT_CORE_FREQUENCY)); 1665b9450e43SRui Paulo DELAY(TRANSITION_LATENCY); 1666b9450e43SRui Paulo /* reset core voltage */ 1667b9450e43SRui Paulo bcm2835_cpufreq_set_voltage(sc, 1668b9450e43SRui Paulo BCM2835_MBOX_VOLTAGE_ID_CORE, 0); 1669b9450e43SRui Paulo DELAY(TRANSITION_LATENCY); 1670b9450e43SRui Paulo } 1671b9450e43SRui Paulo bcm2835_cpufreq_set_clock_rate(sc, 1672b9450e43SRui Paulo BCM2835_MBOX_CLOCK_ID_CORE, 1673b9450e43SRui Paulo MHZ2HZ(sc->core_min_freq)); 1674b9450e43SRui Paulo DELAY(TRANSITION_LATENCY); 1675b9450e43SRui Paulo bcm2835_cpufreq_set_clock_rate(sc, 1676b9450e43SRui Paulo BCM2835_MBOX_CLOCK_ID_SDRAM, 1677b9450e43SRui Paulo MHZ2HZ(sc->sdram_min_freq)); 1678b9450e43SRui Paulo DELAY(TRANSITION_LATENCY); 1679b9450e43SRui Paulo } 1680b9450e43SRui Paulo } 1681b9450e43SRui Paulo 1682b9450e43SRui Paulo VC_UNLOCK(sc); 1683b9450e43SRui Paulo 1684b9450e43SRui Paulo if (resp_freq < 0 || arm_freq < 0 || resp_freq != arm_freq) { 1685b9450e43SRui Paulo device_printf(dev, "wrong freq\n"); 1686b9450e43SRui Paulo return (EIO); 1687b9450e43SRui Paulo } 1688b9450e43SRui Paulo DPRINTF("cpufreq: %d -> %d\n", cur_freq, arm_freq); 1689b9450e43SRui Paulo 1690b9450e43SRui Paulo return (0); 1691b9450e43SRui Paulo } 1692b9450e43SRui Paulo 1693b9450e43SRui Paulo static int 1694b9450e43SRui Paulo bcm2835_cpufreq_get(device_t dev, struct cf_setting *cf) 1695b9450e43SRui Paulo { 1696b9450e43SRui Paulo struct bcm2835_cpufreq_softc *sc; 1697b9450e43SRui Paulo int arm_freq; 1698b9450e43SRui Paulo 1699b9450e43SRui Paulo if (cf == NULL) 1700b9450e43SRui Paulo return (EINVAL); 1701b9450e43SRui Paulo 1702b9450e43SRui Paulo sc = device_get_softc(dev); 1703b9450e43SRui Paulo memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf)); 1704b9450e43SRui Paulo cf->dev = NULL; 1705b9450e43SRui Paulo 1706b9450e43SRui Paulo /* get cuurent value */ 1707b9450e43SRui Paulo VC_LOCK(sc); 1708b9450e43SRui Paulo arm_freq = bcm2835_cpufreq_get_clock_rate(sc, 1709b9450e43SRui Paulo BCM2835_MBOX_CLOCK_ID_ARM); 1710b9450e43SRui Paulo VC_UNLOCK(sc); 1711b9450e43SRui Paulo if (arm_freq < 0) { 1712b9450e43SRui Paulo device_printf(dev, "can't get clock\n"); 1713b9450e43SRui Paulo return (EINVAL); 1714b9450e43SRui Paulo } 1715b9450e43SRui Paulo 1716b9450e43SRui Paulo /* CPU clock in MHz or 100ths of a percent. */ 1717b9450e43SRui Paulo cf->freq = HZ2MHZ(arm_freq); 1718b9450e43SRui Paulo /* Voltage in mV. */ 1719b9450e43SRui Paulo cf->volts = CPUFREQ_VAL_UNKNOWN; 1720b9450e43SRui Paulo /* Power consumed in mW. */ 1721b9450e43SRui Paulo cf->power = CPUFREQ_VAL_UNKNOWN; 1722b9450e43SRui Paulo /* Transition latency in us. */ 1723b9450e43SRui Paulo cf->lat = TRANSITION_LATENCY; 1724b9450e43SRui Paulo /* Driver providing this setting. */ 1725b9450e43SRui Paulo cf->dev = dev; 1726b9450e43SRui Paulo 1727b9450e43SRui Paulo return (0); 1728b9450e43SRui Paulo } 1729b9450e43SRui Paulo 1730b9450e43SRui Paulo static int 1731b9450e43SRui Paulo bcm2835_cpufreq_make_freq_list(device_t dev, struct cf_setting *sets, 1732b9450e43SRui Paulo int *count) 1733b9450e43SRui Paulo { 1734b9450e43SRui Paulo struct bcm2835_cpufreq_softc *sc; 1735b9450e43SRui Paulo int freq, min_freq, volts, rem; 1736b9450e43SRui Paulo int idx; 1737b9450e43SRui Paulo 1738b9450e43SRui Paulo sc = device_get_softc(dev); 1739b9450e43SRui Paulo freq = sc->arm_max_freq; 1740b9450e43SRui Paulo min_freq = sc->arm_min_freq; 1741b9450e43SRui Paulo 1742b9450e43SRui Paulo /* adjust head freq to STEP */ 1743b9450e43SRui Paulo rem = freq % MHZSTEP; 1744b9450e43SRui Paulo freq -= rem; 1745b9450e43SRui Paulo if (freq < min_freq) 1746b9450e43SRui Paulo freq = min_freq; 1747b9450e43SRui Paulo 1748b9450e43SRui Paulo /* if non-turbo, add extra low freq */ 1749b9450e43SRui Paulo if (sc->turbo_mode != BCM2835_MBOX_TURBO_ON) 1750b9450e43SRui Paulo if (min_freq > cpufreq_lowest_freq) 1751b9450e43SRui Paulo min_freq = cpufreq_lowest_freq; 1752b9450e43SRui Paulo 175311cede48SLuiz Otavio O Souza #ifdef SOC_BCM2836 175411cede48SLuiz Otavio O Souza /* XXX RPi2 have only 900/600MHz */ 175511cede48SLuiz Otavio O Souza idx = 0; 175611cede48SLuiz Otavio O Souza volts = sc->min_voltage_core; 175711cede48SLuiz Otavio O Souza sets[idx].freq = freq; 175811cede48SLuiz Otavio O Souza sets[idx].volts = volts; 175911cede48SLuiz Otavio O Souza sets[idx].lat = TRANSITION_LATENCY; 176011cede48SLuiz Otavio O Souza sets[idx].dev = dev; 176111cede48SLuiz Otavio O Souza idx++; 176211cede48SLuiz Otavio O Souza if (freq != min_freq) { 176311cede48SLuiz Otavio O Souza sets[idx].freq = min_freq; 176411cede48SLuiz Otavio O Souza sets[idx].volts = volts; 176511cede48SLuiz Otavio O Souza sets[idx].lat = TRANSITION_LATENCY; 176611cede48SLuiz Otavio O Souza sets[idx].dev = dev; 176711cede48SLuiz Otavio O Souza idx++; 176811cede48SLuiz Otavio O Souza } 176911cede48SLuiz Otavio O Souza #else 1770b9450e43SRui Paulo /* from freq to min_freq */ 1771b9450e43SRui Paulo for (idx = 0; idx < *count && freq >= min_freq; idx++) { 1772b9450e43SRui Paulo if (freq > sc->arm_min_freq) 1773b9450e43SRui Paulo volts = sc->max_voltage_core; 1774b9450e43SRui Paulo else 1775b9450e43SRui Paulo volts = sc->min_voltage_core; 1776b9450e43SRui Paulo sets[idx].freq = freq; 1777b9450e43SRui Paulo sets[idx].volts = volts; 1778b9450e43SRui Paulo sets[idx].lat = TRANSITION_LATENCY; 1779b9450e43SRui Paulo sets[idx].dev = dev; 1780b9450e43SRui Paulo freq -= MHZSTEP; 1781b9450e43SRui Paulo } 178211cede48SLuiz Otavio O Souza #endif 178311cede48SLuiz Otavio O Souza *count = idx; 1784b9450e43SRui Paulo 1785b9450e43SRui Paulo return (0); 1786b9450e43SRui Paulo } 1787b9450e43SRui Paulo 1788b9450e43SRui Paulo static int 1789b9450e43SRui Paulo bcm2835_cpufreq_settings(device_t dev, struct cf_setting *sets, int *count) 1790b9450e43SRui Paulo { 1791b9450e43SRui Paulo struct bcm2835_cpufreq_softc *sc; 1792b9450e43SRui Paulo 1793b9450e43SRui Paulo if (sets == NULL || count == NULL) 1794b9450e43SRui Paulo return (EINVAL); 1795b9450e43SRui Paulo 1796b9450e43SRui Paulo sc = device_get_softc(dev); 1797b9450e43SRui Paulo if (sc->arm_min_freq < 0 || sc->arm_max_freq < 0) { 1798b9450e43SRui Paulo printf("device is not configured\n"); 1799b9450e43SRui Paulo return (EINVAL); 1800b9450e43SRui Paulo } 1801b9450e43SRui Paulo 1802b9450e43SRui Paulo /* fill data with unknown value */ 1803b9450e43SRui Paulo memset(sets, CPUFREQ_VAL_UNKNOWN, sizeof(*sets) * (*count)); 1804b9450e43SRui Paulo /* create new array up to count */ 1805b9450e43SRui Paulo bcm2835_cpufreq_make_freq_list(dev, sets, count); 1806b9450e43SRui Paulo 1807b9450e43SRui Paulo return (0); 1808b9450e43SRui Paulo } 1809b9450e43SRui Paulo 1810b9450e43SRui Paulo static int 1811b9450e43SRui Paulo bcm2835_cpufreq_type(device_t dev, int *type) 1812b9450e43SRui Paulo { 1813b9450e43SRui Paulo 1814b9450e43SRui Paulo if (type == NULL) 1815b9450e43SRui Paulo return (EINVAL); 1816b9450e43SRui Paulo *type = CPUFREQ_TYPE_ABSOLUTE; 1817b9450e43SRui Paulo 1818b9450e43SRui Paulo return (0); 1819b9450e43SRui Paulo } 1820b9450e43SRui Paulo 1821b9450e43SRui Paulo static device_method_t bcm2835_cpufreq_methods[] = { 1822b9450e43SRui Paulo /* Device interface */ 1823b9450e43SRui Paulo DEVMETHOD(device_identify, bcm2835_cpufreq_identify), 1824b9450e43SRui Paulo DEVMETHOD(device_probe, bcm2835_cpufreq_probe), 1825b9450e43SRui Paulo DEVMETHOD(device_attach, bcm2835_cpufreq_attach), 1826b9450e43SRui Paulo DEVMETHOD(device_detach, bcm2835_cpufreq_detach), 1827b9450e43SRui Paulo 1828b9450e43SRui Paulo /* cpufreq interface */ 1829b9450e43SRui Paulo DEVMETHOD(cpufreq_drv_set, bcm2835_cpufreq_set), 1830b9450e43SRui Paulo DEVMETHOD(cpufreq_drv_get, bcm2835_cpufreq_get), 1831b9450e43SRui Paulo DEVMETHOD(cpufreq_drv_settings, bcm2835_cpufreq_settings), 1832b9450e43SRui Paulo DEVMETHOD(cpufreq_drv_type, bcm2835_cpufreq_type), 1833b9450e43SRui Paulo 1834b9450e43SRui Paulo DEVMETHOD_END 1835b9450e43SRui Paulo }; 1836b9450e43SRui Paulo 1837b9450e43SRui Paulo static devclass_t bcm2835_cpufreq_devclass; 1838b9450e43SRui Paulo static driver_t bcm2835_cpufreq_driver = { 1839b9450e43SRui Paulo "bcm2835_cpufreq", 1840b9450e43SRui Paulo bcm2835_cpufreq_methods, 1841b9450e43SRui Paulo sizeof(struct bcm2835_cpufreq_softc), 1842b9450e43SRui Paulo }; 1843b9450e43SRui Paulo 1844b9450e43SRui Paulo DRIVER_MODULE(bcm2835_cpufreq, cpu, bcm2835_cpufreq_driver, 1845b9450e43SRui Paulo bcm2835_cpufreq_devclass, 0, 0); 1846