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); } /* 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_property(&msg, sizeof(msg)); 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_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 */ /* 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_property(&msg, sizeof(msg)); 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_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) */ /* 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_property(&msg, sizeof(msg)); 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); }
int vcio_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int mode, struct thread *td) { int error; void *ptr; uint32_t size; uint8_t *property; error = 0; switch(cmd) { case IOCTL_MBOX_PROPERTY: memcpy (&ptr, arg, sizeof(ptr)); error = copyin(ptr, &size, sizeof(size)); if (error != 0) break; property = malloc(size, M_VCIO, M_WAITOK); if (property == NULL) { error = ENOMEM; break; } error = copyin(ptr, property, size); if (error) { free(property, M_VCIO); break; } error = bcm2835_mbox_property(property, size); if (error) { free(property, M_VCIO); break; } error = copyout(property, ptr, size); free(property, M_VCIO); break; default: error = EINVAL; break; } return (error); }
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) */ /* 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_property(&msg, sizeof(msg)); 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_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 */ /* 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_property(&msg, sizeof(msg)); 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 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 */ /* 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_property(&msg, sizeof(msg)); 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_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) */ /* 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_property(&msg, sizeof(msg)); 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_property(&msg, sizeof(msg)); 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); }