svn commit: r278608 - in stable/10/sys: arm/broadcom/bcm2835 boot/fdt/dts/arm conf dev/ofw powerpc/ofw
Ian Lepore
ian at FreeBSD.org
Thu Feb 12 00:25:34 UTC 2015
Author: ian
Date: Thu Feb 12 00:25:33 2015
New Revision: 278608
URL: https://svnweb.freebsd.org/changeset/base/278608
Log:
MFC r275779, r275963, r276101, r276161, r276297:
Move ofw_cpu.c to sys/dev/ofw so that it can be used by other
architectures.
Add driver for CPU frequency/voltage control on the Raspberry Pi.
On initialization, do not use bcm_mbox_intr() to read the pending messages.
This fixes the hang that happens on boot while initializing the cpufreq on
Raspberry Pi.
Added:
stable/10/sys/arm/broadcom/bcm2835/bcm2835_cpufreq.c
- copied unchanged from r275963, head/sys/arm/broadcom/bcm2835/bcm2835_cpufreq.c
stable/10/sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h
- copied unchanged from r275963, head/sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h
stable/10/sys/dev/ofw/ofw_cpu.c
- copied unchanged from r275779, head/sys/dev/ofw/ofw_cpu.c
Deleted:
stable/10/sys/powerpc/ofw/ofw_cpu.c
Modified:
stable/10/sys/arm/broadcom/bcm2835/bcm2835_mbox.c
stable/10/sys/arm/broadcom/bcm2835/bcm2835_mbox.h
stable/10/sys/arm/broadcom/bcm2835/files.bcm2835
stable/10/sys/boot/fdt/dts/arm/rpi.dts
stable/10/sys/conf/files.powerpc
Directory Properties:
stable/10/ (props changed)
Copied: stable/10/sys/arm/broadcom/bcm2835/bcm2835_cpufreq.c (from r275963, head/sys/arm/broadcom/bcm2835/bcm2835_cpufreq.c)
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ stable/10/sys/arm/broadcom/bcm2835/bcm2835_cpufreq.c Thu Feb 12 00:25:33 2015 (r278608, copy of r275963, head/sys/arm/broadcom/bcm2835/bcm2835_cpufreq.c)
@@ -0,0 +1,1818 @@
+/*-
+ * Copyright (C) 2013-2014 Daisuke Aoyama <aoyama at peach.ne.jp>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/sema.h>
+#include <sys/sysctl.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/intr.h>
+
+#include <arm/broadcom/bcm2835/bcm2835_mbox.h>
+#include <arm/broadcom/bcm2835/bcm2835_mbox_prop.h>
+#include <arm/broadcom/bcm2835/bcm2835_vcbus.h>
+
+#include "cpufreq_if.h"
+#include "mbox_if.h"
+
+#ifdef DEBUG
+#define DPRINTF(fmt, ...) do { \
+ printf("%s:%u: ", __func__, __LINE__); \
+ printf(fmt, ##__VA_ARGS__); \
+} while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+#define HZ2MHZ(freq) ((freq) / (1000 * 1000))
+#define MHZ2HZ(freq) ((freq) * (1000 * 1000))
+#define OFFSET2MVOLT(val) (1200 + ((val) * 25))
+#define MVOLT2OFFSET(val) (((val) - 1200) / 25)
+#define RAW2K(temp) (((temp) + 273150) / 1000)
+#define K2RAW(temp) (((temp) * 1000) - 273150)
+
+#define DEFAULT_ARM_FREQUENCY 700
+#define DEFAULT_CORE_FREQUENCY 250
+#define DEFAULT_SDRAM_FREQUENCY 400
+#define DEFAULT_LOWEST_FREQ 300
+#define TRANSITION_LATENCY 1000
+#define MIN_OVER_VOLTAGE -16
+#define MAX_OVER_VOLTAGE 6
+#define MSG_ERROR -999999999
+#define MHZSTEP 100
+#define HZSTEP (MHZ2HZ(MHZSTEP))
+
+#define VC_LOCK(sc) do { \
+ sema_wait(&vc_sema); \
+ } while (0)
+#define VC_UNLOCK(sc) do { \
+ sema_post(&vc_sema); \
+ } while (0)
+
+/* ARM->VC mailbox property semaphore */
+static struct sema vc_sema;
+
+static struct sysctl_ctx_list bcm2835_sysctl_ctx;
+
+struct bcm2835_cpufreq_softc {
+ device_t dev;
+ int arm_max_freq;
+ int arm_min_freq;
+ int core_max_freq;
+ int core_min_freq;
+ int sdram_max_freq;
+ int sdram_min_freq;
+ int max_voltage_core;
+ int min_voltage_core;
+
+ /* the values written in mbox */
+ int voltage_core;
+ int voltage_sdram;
+ int voltage_sdram_c;
+ int voltage_sdram_i;
+ int voltage_sdram_p;
+ int turbo_mode;
+
+ /* mbox buffer (physical address) */
+ bus_dma_tag_t dma_tag;
+ bus_dmamap_t dma_map;
+ bus_size_t dma_size;
+ void *dma_buf;
+ bus_addr_t dma_phys;
+
+ /* initial hook for waiting mbox intr */
+ struct intr_config_hook init_hook;
+};
+
+static int cpufreq_verbose = 0;
+TUNABLE_INT("hw.bcm2835.cpufreq.verbose", &cpufreq_verbose);
+static int cpufreq_lowest_freq = DEFAULT_LOWEST_FREQ;
+TUNABLE_INT("hw.bcm2835.cpufreq.lowest_freq", &cpufreq_lowest_freq);
+
+#ifdef DEBUG
+static void
+bcm2835_dump(const void *data, int len)
+{
+ const uint8_t *p = (const uint8_t*)data;
+ int i;
+
+ printf("dump @ %p:\n", data);
+ for (i = 0; i < len; i++) {
+ printf("%2.2x ", p[i]);
+ if ((i % 4) == 3)
+ printf(" ");
+ if ((i % 16) == 15)
+ printf("\n");
+ }
+ printf("\n");
+}
+#endif
+
+static int
+bcm2835_mbox_call_prop(struct bcm2835_cpufreq_softc *sc)
+{
+ struct bcm2835_mbox_hdr *msg = (struct bcm2835_mbox_hdr *)sc->dma_buf;
+ struct bcm2835_mbox_tag_hdr *tag, *last;
+ uint8_t *up;
+ device_t mbox;
+ size_t hdr_size;
+ int idx;
+ int err;
+
+ /*
+ * For multiple calls, locking is not here. The caller must have
+ * VC semaphore.
+ */
+
+ /* get mbox device */
+ mbox = devclass_get_device(devclass_find("mbox"), 0);
+ if (mbox == NULL) {
+ device_printf(sc->dev, "can't find mbox\n");
+ return (-1);
+ }
+
+ /* go mailbox property */
+#ifdef PROP_DEBUG
+ bcm2835_dump(msg, 64);
+#endif
+ bus_dmamap_sync(sc->dma_tag, sc->dma_map,
+ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+ MBOX_WRITE(mbox, BCM2835_MBOX_CHAN_PROP, (uint32_t)sc->dma_phys);
+ MBOX_READ(mbox, BCM2835_MBOX_CHAN_PROP, &err);
+ bus_dmamap_sync(sc->dma_tag, sc->dma_map, BUS_DMASYNC_POSTREAD);
+#ifdef PROP_DEBUG
+ bcm2835_dump(msg, 64);
+#endif
+
+ /* check response code */
+ if (msg->code != BCM2835_MBOX_CODE_RESP_SUCCESS) {
+ device_printf(sc->dev, "mbox response error\n");
+ return (-1);
+ }
+
+ /* tag = first tag */
+ up = (uint8_t *)msg;
+ hdr_size = sizeof(struct bcm2835_mbox_hdr);
+ tag = (struct bcm2835_mbox_tag_hdr *)(up + hdr_size);
+ /* last = end of buffer specified by header */
+ last = (struct bcm2835_mbox_tag_hdr *)(up + msg->buf_size);
+
+ /* loop unitl end tag (=0x0) */
+ hdr_size = sizeof(struct bcm2835_mbox_tag_hdr);
+ for (idx = 0; tag->tag != 0; idx++) {
+ if ((tag->val_len & BCM2835_MBOX_TAG_VAL_LEN_RESPONSE) == 0) {
+ device_printf(sc->dev, "tag%d response error\n", idx);
+ return (-1);
+ }
+ /* clear response bit */
+ tag->val_len &= ~BCM2835_MBOX_TAG_VAL_LEN_RESPONSE;
+
+ /* get next tag */
+ up = (uint8_t *)tag;
+ tag = (struct bcm2835_mbox_tag_hdr *)(up + hdr_size +
+ tag->val_buf_size);
+
+ /* check buffer size of header */
+ if (tag > last) {
+ device_printf(sc->dev, "mbox buffer size error\n");
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+static int
+bcm2835_cpufreq_get_clock_rate(struct bcm2835_cpufreq_softc *sc,
+ uint32_t clock_id)
+{
+ struct msg_get_clock_rate *msg;
+ int rate;
+ int err;
+
+ /*
+ * Get clock rate
+ * Tag: 0x00030002
+ * Request:
+ * Length: 4
+ * Value:
+ * u32: clock id
+ * Response:
+ * Length: 8
+ * Value:
+ * u32: clock id
+ * u32: rate (in Hz)
+ */
+
+ /* using DMA buffer for VC */
+ msg = (struct msg_get_clock_rate *)sc->dma_buf;
+ if (sizeof(*msg) > sc->dma_size) {
+ device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n",
+ sizeof(*msg), sc->dma_size);
+ return (MSG_ERROR);
+ }
+
+ /* setup single tag buffer */
+ memset(msg, 0, sizeof(*msg));
+ msg->hdr.buf_size = sizeof(*msg);
+ msg->hdr.code = BCM2835_MBOX_CODE_REQ;
+ msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_CLOCK_RATE;
+ msg->tag_hdr.val_buf_size = sizeof(msg->body);
+ msg->tag_hdr.val_len = sizeof(msg->body.req);
+ msg->body.req.clock_id = clock_id;
+ msg->end_tag = 0;
+
+ /* call mailbox property */
+ err = bcm2835_mbox_call_prop(sc);
+ if (err) {
+ device_printf(sc->dev, "can't get clock rate (id=%u)\n",
+ clock_id);
+ return (MSG_ERROR);
+ }
+
+ /* result (Hz) */
+ rate = (int)msg->body.resp.rate_hz;
+ DPRINTF("clock = %d(Hz)\n", rate);
+ return (rate);
+}
+
+static int
+bcm2835_cpufreq_get_max_clock_rate(struct bcm2835_cpufreq_softc *sc,
+ uint32_t clock_id)
+{
+ struct msg_get_max_clock_rate *msg;
+ int rate;
+ int err;
+
+ /*
+ * Get max clock rate
+ * Tag: 0x00030004
+ * Request:
+ * Length: 4
+ * Value:
+ * u32: clock id
+ * Response:
+ * Length: 8
+ * Value:
+ * u32: clock id
+ * u32: rate (in Hz)
+ */
+
+ /* using DMA buffer for VC */
+ msg = (struct msg_get_max_clock_rate *)sc->dma_buf;
+ if (sizeof(*msg) > sc->dma_size) {
+ device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n",
+ sizeof(*msg), sc->dma_size);
+ return (MSG_ERROR);
+ }
+
+ /* setup single tag buffer */
+ memset(msg, 0, sizeof(*msg));
+ msg->hdr.buf_size = sizeof(*msg);
+ msg->hdr.code = BCM2835_MBOX_CODE_REQ;
+ msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_MAX_CLOCK_RATE;
+ msg->tag_hdr.val_buf_size = sizeof(msg->body);
+ msg->tag_hdr.val_len = sizeof(msg->body.req);
+ msg->body.req.clock_id = clock_id;
+ msg->end_tag = 0;
+
+ /* call mailbox property */
+ err = bcm2835_mbox_call_prop(sc);
+ if (err) {
+ device_printf(sc->dev, "can't get max clock rate (id=%u)\n",
+ clock_id);
+ return (MSG_ERROR);
+ }
+
+ /* result (Hz) */
+ rate = (int)msg->body.resp.rate_hz;
+ DPRINTF("clock = %d(Hz)\n", rate);
+ return (rate);
+}
+
+static int
+bcm2835_cpufreq_get_min_clock_rate(struct bcm2835_cpufreq_softc *sc,
+ uint32_t clock_id)
+{
+ struct msg_get_min_clock_rate *msg;
+ int rate;
+ int err;
+
+ /*
+ * Get min clock rate
+ * Tag: 0x00030007
+ * Request:
+ * Length: 4
+ * Value:
+ * u32: clock id
+ * Response:
+ * Length: 8
+ * Value:
+ * u32: clock id
+ * u32: rate (in Hz)
+ */
+
+ /* using DMA buffer for VC */
+ msg = (struct msg_get_min_clock_rate *)sc->dma_buf;
+ if (sizeof(*msg) > sc->dma_size) {
+ device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n",
+ sizeof(*msg), sc->dma_size);
+ return (MSG_ERROR);
+ }
+
+ /* setup single tag buffer */
+ memset(msg, 0, sizeof(*msg));
+ msg->hdr.buf_size = sizeof(*msg);
+ msg->hdr.code = BCM2835_MBOX_CODE_REQ;
+ msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_MIN_CLOCK_RATE;
+ msg->tag_hdr.val_buf_size = sizeof(msg->body);
+ msg->tag_hdr.val_len = sizeof(msg->body.req);
+ msg->body.req.clock_id = clock_id;
+ msg->end_tag = 0;
+
+ /* call mailbox property */
+ err = bcm2835_mbox_call_prop(sc);
+ if (err) {
+ device_printf(sc->dev, "can't get min clock rate (id=%u)\n",
+ clock_id);
+ return (MSG_ERROR);
+ }
+
+ /* result (Hz) */
+ rate = (int)msg->body.resp.rate_hz;
+ DPRINTF("clock = %d(Hz)\n", rate);
+ return (rate);
+}
+
+static int
+bcm2835_cpufreq_set_clock_rate(struct bcm2835_cpufreq_softc *sc,
+ uint32_t clock_id, uint32_t rate_hz)
+{
+ struct msg_set_clock_rate *msg;
+ int rate;
+ int err;
+
+ /*
+ * Set clock rate
+ * Tag: 0x00038002
+ * Request:
+ * Length: 8
+ * Value:
+ * u32: clock id
+ * u32: rate (in Hz)
+ * Response:
+ * Length: 8
+ * Value:
+ * u32: clock id
+ * u32: rate (in Hz)
+ */
+
+ /* using DMA buffer for VC */
+ msg = (struct msg_set_clock_rate *)sc->dma_buf;
+ if (sizeof(*msg) > sc->dma_size) {
+ device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n",
+ sizeof(*msg), sc->dma_size);
+ return (MSG_ERROR);
+ }
+
+ /* setup single tag buffer */
+ memset(msg, 0, sizeof(*msg));
+ msg->hdr.buf_size = sizeof(*msg);
+ msg->hdr.code = BCM2835_MBOX_CODE_REQ;
+ msg->tag_hdr.tag = BCM2835_MBOX_TAG_SET_CLOCK_RATE;
+ msg->tag_hdr.val_buf_size = sizeof(msg->body);
+ msg->tag_hdr.val_len = sizeof(msg->body.req);
+ msg->body.req.clock_id = clock_id;
+ msg->body.req.rate_hz = rate_hz;
+ msg->end_tag = 0;
+
+ /* call mailbox property */
+ err = bcm2835_mbox_call_prop(sc);
+ if (err) {
+ device_printf(sc->dev, "can't set clock rate (id=%u)\n",
+ clock_id);
+ return (MSG_ERROR);
+ }
+
+ /* workaround for core clock */
+ if (clock_id == BCM2835_MBOX_CLOCK_ID_CORE) {
+ /* for safety (may change voltage without changing clock) */
+ DELAY(TRANSITION_LATENCY);
+
+ /*
+ * XXX: the core clock is unable to change at once,
+ * to change certainly, write it twice now.
+ */
+
+ /* setup single tag buffer */
+ memset(msg, 0, sizeof(*msg));
+ msg->hdr.buf_size = sizeof(*msg);
+ msg->hdr.code = BCM2835_MBOX_CODE_REQ;
+ msg->tag_hdr.tag = BCM2835_MBOX_TAG_SET_CLOCK_RATE;
+ msg->tag_hdr.val_buf_size = sizeof(msg->body);
+ msg->tag_hdr.val_len = sizeof(msg->body.req);
+ msg->body.req.clock_id = clock_id;
+ msg->body.req.rate_hz = rate_hz;
+ msg->end_tag = 0;
+
+ /* call mailbox property */
+ err = bcm2835_mbox_call_prop(sc);
+ if (err) {
+ device_printf(sc->dev,
+ "can't set clock rate (id=%u)\n", clock_id);
+ return (MSG_ERROR);
+ }
+ }
+
+ /* result (Hz) */
+ rate = (int)msg->body.resp.rate_hz;
+ DPRINTF("clock = %d(Hz)\n", rate);
+ return (rate);
+}
+
+static int
+bcm2835_cpufreq_get_turbo(struct bcm2835_cpufreq_softc *sc)
+{
+ struct msg_get_turbo *msg;
+ int level;
+ int err;
+
+ /*
+ * Get turbo
+ * Tag: 0x00030009
+ * Request:
+ * Length: 4
+ * Value:
+ * u32: id
+ * Response:
+ * Length: 8
+ * Value:
+ * u32: id
+ * u32: level
+ */
+
+ /* using DMA buffer for VC */
+ msg = (struct msg_get_turbo *)sc->dma_buf;
+ if (sizeof(*msg) > sc->dma_size) {
+ device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n",
+ sizeof(*msg), sc->dma_size);
+ return (MSG_ERROR);
+ }
+
+ /* setup single tag buffer */
+ memset(msg, 0, sizeof(*msg));
+ msg->hdr.buf_size = sizeof(*msg);
+ msg->hdr.code = BCM2835_MBOX_CODE_REQ;
+ msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_TURBO;
+ msg->tag_hdr.val_buf_size = sizeof(msg->body);
+ msg->tag_hdr.val_len = sizeof(msg->body.req);
+ msg->body.req.id = 0;
+ msg->end_tag = 0;
+
+ /* call mailbox property */
+ err = bcm2835_mbox_call_prop(sc);
+ if (err) {
+ device_printf(sc->dev, "can't get turbo\n");
+ return (MSG_ERROR);
+ }
+
+ /* result 0=non-turbo, 1=turbo */
+ level = (int)msg->body.resp.level;
+ DPRINTF("level = %d\n", level);
+ return (level);
+}
+
+static int
+bcm2835_cpufreq_set_turbo(struct bcm2835_cpufreq_softc *sc, uint32_t level)
+{
+ struct msg_set_turbo *msg;
+ int value;
+ int err;
+
+ /*
+ * Set turbo
+ * Tag: 0x00038009
+ * Request:
+ * Length: 8
+ * Value:
+ * u32: id
+ * u32: level
+ * Response:
+ * Length: 8
+ * Value:
+ * u32: id
+ * u32: level
+ */
+
+ /* using DMA buffer for VC */
+ msg = (struct msg_set_turbo *)sc->dma_buf;
+ if (sizeof(*msg) > sc->dma_size) {
+ device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n",
+ sizeof(*msg), sc->dma_size);
+ return (MSG_ERROR);
+ }
+
+ /* replace unknown value to OFF */
+ if (level != BCM2835_MBOX_TURBO_ON && level != BCM2835_MBOX_TURBO_OFF)
+ level = BCM2835_MBOX_TURBO_OFF;
+
+ /* setup single tag buffer */
+ memset(msg, 0, sizeof(*msg));
+ msg->hdr.buf_size = sizeof(*msg);
+ msg->hdr.code = BCM2835_MBOX_CODE_REQ;
+ msg->tag_hdr.tag = BCM2835_MBOX_TAG_SET_TURBO;
+ msg->tag_hdr.val_buf_size = sizeof(msg->body);
+ msg->tag_hdr.val_len = sizeof(msg->body.req);
+ msg->body.req.id = 0;
+ msg->body.req.level = level;
+ msg->end_tag = 0;
+
+ /* call mailbox property */
+ err = bcm2835_mbox_call_prop(sc);
+ if (err) {
+ device_printf(sc->dev, "can't set turbo\n");
+ return (MSG_ERROR);
+ }
+
+ /* result 0=non-turbo, 1=turbo */
+ value = (int)msg->body.resp.level;
+ DPRINTF("level = %d\n", value);
+ return (value);
+}
+
+static int
+bcm2835_cpufreq_get_voltage(struct bcm2835_cpufreq_softc *sc,
+ uint32_t voltage_id)
+{
+ struct msg_get_voltage *msg;
+ int value;
+ int err;
+
+ /*
+ * Get voltage
+ * Tag: 0x00030003
+ * Request:
+ * Length: 4
+ * Value:
+ * u32: voltage id
+ * Response:
+ * Length: 8
+ * Value:
+ * u32: voltage id
+ * u32: value (offset from 1.2V in units of 0.025V)
+ */
+
+ /* using DMA buffer for VC */
+ msg = (struct msg_get_voltage *)sc->dma_buf;
+ if (sizeof(*msg) > sc->dma_size) {
+ device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n",
+ sizeof(*msg), sc->dma_size);
+ return (MSG_ERROR);
+ }
+
+ /* setup single tag buffer */
+ memset(msg, 0, sizeof(*msg));
+ msg->hdr.buf_size = sizeof(*msg);
+ msg->hdr.code = BCM2835_MBOX_CODE_REQ;
+ msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_VOLTAGE;
+ msg->tag_hdr.val_buf_size = sizeof(msg->body);
+ msg->tag_hdr.val_len = sizeof(msg->body.req);
+ msg->body.req.voltage_id = voltage_id;
+ msg->end_tag = 0;
+
+ /* call mailbox property */
+ err = bcm2835_mbox_call_prop(sc);
+ if (err) {
+ device_printf(sc->dev, "can't get voltage\n");
+ return (MSG_ERROR);
+ }
+
+ /* result (offset from 1.2V) */
+ value = (int)msg->body.resp.value;
+ DPRINTF("value = %d\n", value);
+ return (value);
+}
+
+static int
+bcm2835_cpufreq_get_max_voltage(struct bcm2835_cpufreq_softc *sc,
+ uint32_t voltage_id)
+{
+ struct msg_get_max_voltage *msg;
+ int value;
+ int err;
+
+ /*
+ * Get voltage
+ * Tag: 0x00030005
+ * Request:
+ * Length: 4
+ * Value:
+ * u32: voltage id
+ * Response:
+ * Length: 8
+ * Value:
+ * u32: voltage id
+ * u32: value (offset from 1.2V in units of 0.025V)
+ */
+
+ /* using DMA buffer for VC */
+ msg = (struct msg_get_max_voltage *)sc->dma_buf;
+ if (sizeof(*msg) > sc->dma_size) {
+ device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n",
+ sizeof(*msg), sc->dma_size);
+ return (MSG_ERROR);
+ }
+
+ /* setup single tag buffer */
+ memset(msg, 0, sizeof(*msg));
+ msg->hdr.buf_size = sizeof(*msg);
+ msg->hdr.code = BCM2835_MBOX_CODE_REQ;
+ msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_MAX_VOLTAGE;
+ msg->tag_hdr.val_buf_size = sizeof(msg->body);
+ msg->tag_hdr.val_len = sizeof(msg->body.req);
+ msg->body.req.voltage_id = voltage_id;
+ msg->end_tag = 0;
+
+ /* call mailbox property */
+ err = bcm2835_mbox_call_prop(sc);
+ if (err) {
+ device_printf(sc->dev, "can't get max voltage\n");
+ return (MSG_ERROR);
+ }
+
+ /* result (offset from 1.2V) */
+ value = (int)msg->body.resp.value;
+ DPRINTF("value = %d\n", value);
+ return (value);
+}
+static int
+bcm2835_cpufreq_get_min_voltage(struct bcm2835_cpufreq_softc *sc,
+ uint32_t voltage_id)
+{
+ struct msg_get_min_voltage *msg;
+ int value;
+ int err;
+
+ /*
+ * Get voltage
+ * Tag: 0x00030008
+ * Request:
+ * Length: 4
+ * Value:
+ * u32: voltage id
+ * Response:
+ * Length: 8
+ * Value:
+ * u32: voltage id
+ * u32: value (offset from 1.2V in units of 0.025V)
+ */
+
+ /* using DMA buffer for VC */
+ msg = (struct msg_get_min_voltage *)sc->dma_buf;
+ if (sizeof(*msg) > sc->dma_size) {
+ device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n",
+ sizeof(*msg), sc->dma_size);
+ return (MSG_ERROR);
+ }
+
+ /* setup single tag buffer */
+ memset(msg, 0, sizeof(*msg));
+ msg->hdr.buf_size = sizeof(*msg);
+ msg->hdr.code = BCM2835_MBOX_CODE_REQ;
+ msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_MIN_VOLTAGE;
+ msg->tag_hdr.val_buf_size = sizeof(msg->body);
+ msg->tag_hdr.val_len = sizeof(msg->body.req);
+ msg->body.req.voltage_id = voltage_id;
+ msg->end_tag = 0;
+
+ /* call mailbox property */
+ err = bcm2835_mbox_call_prop(sc);
+ if (err) {
+ device_printf(sc->dev, "can't get min voltage\n");
+ return (MSG_ERROR);
+ }
+
+ /* result (offset from 1.2V) */
+ value = (int)msg->body.resp.value;
+ DPRINTF("value = %d\n", value);
+ return (value);
+}
+
+static int
+bcm2835_cpufreq_set_voltage(struct bcm2835_cpufreq_softc *sc,
+ uint32_t voltage_id, int32_t value)
+{
+ struct msg_set_voltage *msg;
+ int err;
+
+ /*
+ * Set voltage
+ * Tag: 0x00038003
+ * Request:
+ * Length: 4
+ * Value:
+ * u32: voltage id
+ * u32: value (offset from 1.2V in units of 0.025V)
+ * Response:
+ * Length: 8
+ * Value:
+ * u32: voltage id
+ * u32: value (offset from 1.2V in units of 0.025V)
+ */
+
+ /*
+ * over_voltage:
+ * 0 (1.2 V). Values above 6 are only allowed when force_turbo or
+ * current_limit_override are specified (which set the warranty bit).
+ */
+ if (value > MAX_OVER_VOLTAGE || value < MIN_OVER_VOLTAGE) {
+ /* currently not supported */
+ device_printf(sc->dev, "not supported voltage: %d\n", value);
+ return (MSG_ERROR);
+ }
+
+ /* using DMA buffer for VC */
+ msg = (struct msg_set_voltage *)sc->dma_buf;
+ if (sizeof(*msg) > sc->dma_size) {
+ device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n",
+ sizeof(*msg), sc->dma_size);
+ return (MSG_ERROR);
+ }
+
+ /* setup single tag buffer */
+ memset(msg, 0, sizeof(*msg));
+ msg->hdr.buf_size = sizeof(*msg);
+ msg->hdr.code = BCM2835_MBOX_CODE_REQ;
+ msg->tag_hdr.tag = BCM2835_MBOX_TAG_SET_VOLTAGE;
+ msg->tag_hdr.val_buf_size = sizeof(msg->body);
+ msg->tag_hdr.val_len = sizeof(msg->body.req);
+ msg->body.req.voltage_id = voltage_id;
+ msg->body.req.value = (uint32_t)value;
+ msg->end_tag = 0;
+
+ /* call mailbox property */
+ err = bcm2835_mbox_call_prop(sc);
+ if (err) {
+ device_printf(sc->dev, "can't set voltage\n");
+ return (MSG_ERROR);
+ }
+
+ /* result (offset from 1.2V) */
+ value = (int)msg->body.resp.value;
+ DPRINTF("value = %d\n", value);
+ return (value);
+}
+
+static int
+bcm2835_cpufreq_get_temperature(struct bcm2835_cpufreq_softc *sc)
+{
+ struct msg_get_temperature *msg;
+ int value;
+ int err;
+
+ /*
+ * Get temperature
+ * Tag: 0x00030006
+ * Request:
+ * Length: 4
+ * Value:
+ * u32: temperature id
+ * Response:
+ * Length: 8
+ * Value:
+ * u32: temperature id
+ * u32: value
+ */
+
+ /* using DMA buffer for VC */
+ msg = (struct msg_get_temperature *)sc->dma_buf;
+ if (sizeof(*msg) > sc->dma_size) {
+ device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n",
+ sizeof(*msg), sc->dma_size);
+ return (MSG_ERROR);
+ }
+
+ /* setup single tag buffer */
+ memset(msg, 0, sizeof(*msg));
+ msg->hdr.buf_size = sizeof(*msg);
+ msg->hdr.code = BCM2835_MBOX_CODE_REQ;
+ msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_TEMPERATURE;
+ msg->tag_hdr.val_buf_size = sizeof(msg->body);
+ msg->tag_hdr.val_len = sizeof(msg->body.req);
+ msg->body.req.temperature_id = 0;
+ msg->end_tag = 0;
+
+ /* call mailbox property */
+ err = bcm2835_mbox_call_prop(sc);
+ if (err) {
+ device_printf(sc->dev, "can't get temperature\n");
+ return (MSG_ERROR);
+ }
+
+ /* result (temperature of degree C) */
+ value = (int)msg->body.resp.value;
+ DPRINTF("value = %d\n", value);
+ return (value);
+}
+
+
+
+static int
+sysctl_bcm2835_cpufreq_arm_freq(SYSCTL_HANDLER_ARGS)
+{
+ struct bcm2835_cpufreq_softc *sc = arg1;
+ int val;
+ int err;
+
+ /* get realtime value */
+ VC_LOCK(sc);
+ val = bcm2835_cpufreq_get_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_ARM);
+ VC_UNLOCK(sc);
+ if (val == MSG_ERROR)
+ return (EIO);
+
+ err = sysctl_handle_int(oidp, &val, 0, req);
+ if (err || !req->newptr) /* error || read request */
+ return (err);
+
+ /* write request */
+ VC_LOCK(sc);
+ err = bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_ARM,
+ val);
+ VC_UNLOCK(sc);
+ if (err == MSG_ERROR) {
+ device_printf(sc->dev, "set clock arm_freq error\n");
+ return (EIO);
+ }
+ DELAY(TRANSITION_LATENCY);
+
+ return (0);
+}
+
+static int
+sysctl_bcm2835_cpufreq_core_freq(SYSCTL_HANDLER_ARGS)
+{
+ struct bcm2835_cpufreq_softc *sc = arg1;
+ int val;
+ int err;
+
+ /* get realtime value */
+ VC_LOCK(sc);
+ val = bcm2835_cpufreq_get_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_CORE);
+ VC_UNLOCK(sc);
+ if (val == MSG_ERROR)
+ return (EIO);
+
+ err = sysctl_handle_int(oidp, &val, 0, req);
+ if (err || !req->newptr) /* error || read request */
+ return (err);
+
+ /* write request */
+ VC_LOCK(sc);
+ err = bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_CORE,
+ val);
+ if (err == MSG_ERROR) {
+ VC_UNLOCK(sc);
+ device_printf(sc->dev, "set clock core_freq error\n");
+ return (EIO);
+ }
+ VC_UNLOCK(sc);
+ DELAY(TRANSITION_LATENCY);
+
+ return (0);
+}
+
+static int
+sysctl_bcm2835_cpufreq_sdram_freq(SYSCTL_HANDLER_ARGS)
+{
+ struct bcm2835_cpufreq_softc *sc = arg1;
+ int val;
+ int err;
+
+ /* get realtime value */
+ VC_LOCK(sc);
+ val = bcm2835_cpufreq_get_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_SDRAM);
+ VC_UNLOCK(sc);
+ if (val == MSG_ERROR)
+ return (EIO);
+
+ err = sysctl_handle_int(oidp, &val, 0, req);
+ if (err || !req->newptr) /* error || read request */
+ return (err);
+
+ /* write request */
+ VC_LOCK(sc);
+ err = bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_SDRAM,
+ val);
+ VC_UNLOCK(sc);
+ if (err == MSG_ERROR) {
+ device_printf(sc->dev, "set clock sdram_freq error\n");
+ return (EIO);
+ }
+ DELAY(TRANSITION_LATENCY);
+
+ return (0);
+}
+
+static int
+sysctl_bcm2835_cpufreq_turbo(SYSCTL_HANDLER_ARGS)
+{
+ struct bcm2835_cpufreq_softc *sc = arg1;
+ int val;
+ int err;
+
+ /* get realtime value */
+ VC_LOCK(sc);
+ val = bcm2835_cpufreq_get_turbo(sc);
+ VC_UNLOCK(sc);
+ if (val == MSG_ERROR)
+ return (EIO);
+
+ err = sysctl_handle_int(oidp, &val, 0, req);
+ if (err || !req->newptr) /* error || read request */
+ return (err);
+
+ /* write request */
+ if (val > 0)
+ sc->turbo_mode = BCM2835_MBOX_TURBO_ON;
+ else
+ sc->turbo_mode = BCM2835_MBOX_TURBO_OFF;
+
+ VC_LOCK(sc);
+ err = bcm2835_cpufreq_set_turbo(sc, sc->turbo_mode);
+ VC_UNLOCK(sc);
+ if (err == MSG_ERROR) {
+ device_printf(sc->dev, "set turbo error\n");
+ return (EIO);
+ }
+ DELAY(TRANSITION_LATENCY);
+
+ return (0);
+}
+
+static int
+sysctl_bcm2835_cpufreq_voltage_core(SYSCTL_HANDLER_ARGS)
+{
+ struct bcm2835_cpufreq_softc *sc = arg1;
+ int val;
+ int err;
+
+ /* get realtime value */
+ VC_LOCK(sc);
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-stable-10
mailing list