Changeset View
Changeset View
Standalone View
Standalone View
sys/arm/broadcom/bcm2835/bcm2835_cpufreq.c
Show First 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
#include <machine/cpu.h> | #include <machine/cpu.h> | ||||
#include <machine/intr.h> | #include <machine/intr.h> | ||||
#include <dev/ofw/ofw_bus.h> | #include <dev/ofw/ofw_bus.h> | ||||
#include <dev/ofw/ofw_bus_subr.h> | #include <dev/ofw/ofw_bus_subr.h> | ||||
#include <arm/broadcom/bcm2835/bcm2835_mbox.h> | #include <arm/broadcom/bcm2835/bcm2835_firmware.h> | ||||
#include <arm/broadcom/bcm2835/bcm2835_mbox_prop.h> | |||||
#include <arm/broadcom/bcm2835/bcm2835_vcbus.h> | #include <arm/broadcom/bcm2835/bcm2835_vcbus.h> | ||||
#include "cpufreq_if.h" | #include "cpufreq_if.h" | ||||
#include "mbox_if.h" | |||||
#ifdef DEBUG | #ifdef DEBUG | ||||
#define DPRINTF(fmt, ...) do { \ | #define DPRINTF(fmt, ...) do { \ | ||||
printf("%s:%u: ", __func__, __LINE__); \ | printf("%s:%u: ", __func__, __LINE__); \ | ||||
printf(fmt, ##__VA_ARGS__); \ | printf(fmt, ##__VA_ARGS__); \ | ||||
} while (0) | } while (0) | ||||
#else | #else | ||||
#define DPRINTF(fmt, ...) | #define DPRINTF(fmt, ...) | ||||
Show All 32 Lines | |||||
/* ARM->VC mailbox property semaphore */ | /* ARM->VC mailbox property semaphore */ | ||||
static struct sema vc_sema; | static struct sema vc_sema; | ||||
static struct sysctl_ctx_list bcm2835_sysctl_ctx; | static struct sysctl_ctx_list bcm2835_sysctl_ctx; | ||||
struct bcm2835_cpufreq_softc { | struct bcm2835_cpufreq_softc { | ||||
device_t dev; | device_t dev; | ||||
device_t firmware; | |||||
int arm_max_freq; | int arm_max_freq; | ||||
int arm_min_freq; | int arm_min_freq; | ||||
int core_max_freq; | int core_max_freq; | ||||
int core_min_freq; | int core_min_freq; | ||||
int sdram_max_freq; | int sdram_max_freq; | ||||
int sdram_min_freq; | int sdram_min_freq; | ||||
int max_voltage_core; | int max_voltage_core; | ||||
int min_voltage_core; | int min_voltage_core; | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | bcm2835_dump(const void *data, int len) | ||||
printf("\n"); | printf("\n"); | ||||
} | } | ||||
#endif | #endif | ||||
static int | static int | ||||
bcm2835_cpufreq_get_clock_rate(struct bcm2835_cpufreq_softc *sc, | bcm2835_cpufreq_get_clock_rate(struct bcm2835_cpufreq_softc *sc, | ||||
uint32_t clock_id) | uint32_t clock_id) | ||||
{ | { | ||||
struct msg_get_clock_rate msg; | union msg_get_clock_rate_body msg; | ||||
int rate; | int rate; | ||||
int err; | int err; | ||||
/* | /* | ||||
* Get clock rate | * Get clock rate | ||||
* Tag: 0x00030002 | * Tag: 0x00030002 | ||||
* Request: | * Request: | ||||
* Length: 4 | * Length: 4 | ||||
* Value: | * Value: | ||||
* u32: clock id | * u32: clock id | ||||
* Response: | * Response: | ||||
* Length: 8 | * Length: 8 | ||||
* Value: | * Value: | ||||
* u32: clock id | * u32: clock id | ||||
* u32: rate (in Hz) | * u32: rate (in Hz) | ||||
*/ | */ | ||||
/* setup single tag buffer */ | /* setup single tag buffer */ | ||||
memset(&msg, 0, sizeof(msg)); | memset(&msg, 0, sizeof(msg)); | ||||
msg.hdr.buf_size = sizeof(msg); | msg.req.clock_id = clock_id; | ||||
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 */ | /* call mailbox property */ | ||||
err = bcm2835_mbox_property(&msg, sizeof(msg)); | err = bcm2835_firmware_property(sc->firmware, | ||||
BCM2835_FIRMWARE_TAG_GET_CLOCK_RATE, &msg, sizeof(msg)); | |||||
if (err) { | if (err) { | ||||
device_printf(sc->dev, "can't get clock rate (id=%u)\n", | device_printf(sc->dev, "can't get clock rate (id=%u)\n", | ||||
clock_id); | clock_id); | ||||
return (MSG_ERROR); | return (MSG_ERROR); | ||||
} | } | ||||
/* result (Hz) */ | /* result (Hz) */ | ||||
rate = (int)msg.body.resp.rate_hz; | rate = (int)msg.resp.rate_hz; | ||||
DPRINTF("clock = %d(Hz)\n", rate); | DPRINTF("clock = %d(Hz)\n", rate); | ||||
return (rate); | return (rate); | ||||
} | } | ||||
static int | static int | ||||
bcm2835_cpufreq_get_max_clock_rate(struct bcm2835_cpufreq_softc *sc, | bcm2835_cpufreq_get_max_clock_rate(struct bcm2835_cpufreq_softc *sc, | ||||
uint32_t clock_id) | uint32_t clock_id) | ||||
{ | { | ||||
struct msg_get_max_clock_rate msg; | union msg_get_clock_rate_body msg; | ||||
int rate; | int rate; | ||||
int err; | int err; | ||||
/* | /* | ||||
* Get max clock rate | * Get max clock rate | ||||
* Tag: 0x00030004 | * Tag: 0x00030004 | ||||
* Request: | * Request: | ||||
* Length: 4 | * Length: 4 | ||||
* Value: | * Value: | ||||
* u32: clock id | * u32: clock id | ||||
* Response: | * Response: | ||||
* Length: 8 | * Length: 8 | ||||
* Value: | * Value: | ||||
* u32: clock id | * u32: clock id | ||||
* u32: rate (in Hz) | * u32: rate (in Hz) | ||||
*/ | */ | ||||
/* setup single tag buffer */ | /* setup single tag buffer */ | ||||
memset(&msg, 0, sizeof(msg)); | memset(&msg, 0, sizeof(msg)); | ||||
msg.hdr.buf_size = sizeof(msg); | msg.req.clock_id = clock_id; | ||||
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 */ | /* call mailbox property */ | ||||
err = bcm2835_mbox_property(&msg, sizeof(msg)); | err = bcm2835_firmware_property(sc->firmware, | ||||
BCM2835_FIRMWARE_TAG_GET_MAX_CLOCK_RATE, &msg, sizeof(msg)); | |||||
if (err) { | if (err) { | ||||
device_printf(sc->dev, "can't get max clock rate (id=%u)\n", | device_printf(sc->dev, "can't get max clock rate (id=%u)\n", | ||||
clock_id); | clock_id); | ||||
return (MSG_ERROR); | return (MSG_ERROR); | ||||
} | } | ||||
/* result (Hz) */ | /* result (Hz) */ | ||||
rate = (int)msg.body.resp.rate_hz; | rate = (int)msg.resp.rate_hz; | ||||
DPRINTF("clock = %d(Hz)\n", rate); | DPRINTF("clock = %d(Hz)\n", rate); | ||||
return (rate); | return (rate); | ||||
} | } | ||||
static int | static int | ||||
bcm2835_cpufreq_get_min_clock_rate(struct bcm2835_cpufreq_softc *sc, | bcm2835_cpufreq_get_min_clock_rate(struct bcm2835_cpufreq_softc *sc, | ||||
uint32_t clock_id) | uint32_t clock_id) | ||||
{ | { | ||||
struct msg_get_min_clock_rate msg; | union msg_get_clock_rate_body msg; | ||||
int rate; | int rate; | ||||
int err; | int err; | ||||
/* | /* | ||||
* Get min clock rate | * Get min clock rate | ||||
* Tag: 0x00030007 | * Tag: 0x00030007 | ||||
* Request: | * Request: | ||||
* Length: 4 | * Length: 4 | ||||
* Value: | * Value: | ||||
* u32: clock id | * u32: clock id | ||||
* Response: | * Response: | ||||
* Length: 8 | * Length: 8 | ||||
* Value: | * Value: | ||||
* u32: clock id | * u32: clock id | ||||
* u32: rate (in Hz) | * u32: rate (in Hz) | ||||
*/ | */ | ||||
/* setup single tag buffer */ | /* setup single tag buffer */ | ||||
memset(&msg, 0, sizeof(msg)); | memset(&msg, 0, sizeof(msg)); | ||||
msg.hdr.buf_size = sizeof(msg); | msg.req.clock_id = clock_id; | ||||
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 */ | /* call mailbox property */ | ||||
err = bcm2835_mbox_property(&msg, sizeof(msg)); | err = bcm2835_firmware_property(sc->firmware, | ||||
BCM2835_FIRMWARE_TAG_GET_MIN_CLOCK_RATE, &msg, sizeof(msg)); | |||||
if (err) { | if (err) { | ||||
device_printf(sc->dev, "can't get min clock rate (id=%u)\n", | device_printf(sc->dev, "can't get min clock rate (id=%u)\n", | ||||
clock_id); | clock_id); | ||||
return (MSG_ERROR); | return (MSG_ERROR); | ||||
} | } | ||||
/* result (Hz) */ | /* result (Hz) */ | ||||
rate = (int)msg.body.resp.rate_hz; | rate = (int)msg.resp.rate_hz; | ||||
DPRINTF("clock = %d(Hz)\n", rate); | DPRINTF("clock = %d(Hz)\n", rate); | ||||
return (rate); | return (rate); | ||||
} | } | ||||
static int | static int | ||||
bcm2835_cpufreq_set_clock_rate(struct bcm2835_cpufreq_softc *sc, | bcm2835_cpufreq_set_clock_rate(struct bcm2835_cpufreq_softc *sc, | ||||
uint32_t clock_id, uint32_t rate_hz) | uint32_t clock_id, uint32_t rate_hz) | ||||
{ | { | ||||
struct msg_set_clock_rate msg; | union msg_set_clock_rate_body msg; | ||||
int rate; | int rate; | ||||
int err; | int err; | ||||
/* | /* | ||||
* Set clock rate | * Set clock rate | ||||
* Tag: 0x00038002 | * Tag: 0x00038002 | ||||
* Request: | * Request: | ||||
* Length: 8 | * Length: 8 | ||||
* Value: | * Value: | ||||
* u32: clock id | * u32: clock id | ||||
* u32: rate (in Hz) | * u32: rate (in Hz) | ||||
* Response: | * Response: | ||||
* Length: 8 | * Length: 8 | ||||
* Value: | * Value: | ||||
* u32: clock id | * u32: clock id | ||||
* u32: rate (in Hz) | * u32: rate (in Hz) | ||||
*/ | */ | ||||
/* setup single tag buffer */ | /* setup single tag buffer */ | ||||
memset(&msg, 0, sizeof(msg)); | memset(&msg, 0, sizeof(msg)); | ||||
msg.hdr.buf_size = sizeof(msg); | msg.req.clock_id = clock_id; | ||||
msg.hdr.code = BCM2835_MBOX_CODE_REQ; | msg.req.rate_hz = rate_hz; | ||||
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 */ | /* call mailbox property */ | ||||
err = bcm2835_mbox_property(&msg, sizeof(msg)); | err = bcm2835_firmware_property(sc->firmware, | ||||
BCM2835_FIRMWARE_TAG_SET_CLOCK_RATE, &msg, sizeof(msg)); | |||||
if (err) { | if (err) { | ||||
device_printf(sc->dev, "can't set clock rate (id=%u)\n", | device_printf(sc->dev, "can't set clock rate (id=%u)\n", | ||||
clock_id); | clock_id); | ||||
return (MSG_ERROR); | return (MSG_ERROR); | ||||
} | } | ||||
/* workaround for core clock */ | /* workaround for core clock */ | ||||
if (clock_id == BCM2835_MBOX_CLOCK_ID_CORE) { | if (clock_id == BCM2835_FIRMWARE_CLOCK_ID_CORE) { | ||||
/* for safety (may change voltage without changing clock) */ | /* for safety (may change voltage without changing clock) */ | ||||
DELAY(TRANSITION_LATENCY); | DELAY(TRANSITION_LATENCY); | ||||
/* | /* | ||||
* XXX: the core clock is unable to change at once, | * XXX: the core clock is unable to change at once, | ||||
* to change certainly, write it twice now. | * to change certainly, write it twice now. | ||||
*/ | */ | ||||
/* setup single tag buffer */ | /* setup single tag buffer */ | ||||
memset(&msg, 0, sizeof(msg)); | memset(&msg, 0, sizeof(msg)); | ||||
msg.hdr.buf_size = sizeof(msg); | msg.req.clock_id = clock_id; | ||||
msg.hdr.code = BCM2835_MBOX_CODE_REQ; | msg.req.rate_hz = rate_hz; | ||||
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 */ | /* call mailbox property */ | ||||
err = bcm2835_mbox_property(&msg, sizeof(msg)); | err = bcm2835_firmware_property(sc->firmware, | ||||
BCM2835_FIRMWARE_TAG_SET_CLOCK_RATE, &msg, sizeof(msg)); | |||||
if (err) { | if (err) { | ||||
device_printf(sc->dev, | device_printf(sc->dev, | ||||
"can't set clock rate (id=%u)\n", clock_id); | "can't set clock rate (id=%u)\n", clock_id); | ||||
return (MSG_ERROR); | return (MSG_ERROR); | ||||
} | } | ||||
} | } | ||||
/* result (Hz) */ | /* result (Hz) */ | ||||
rate = (int)msg.body.resp.rate_hz; | rate = (int)msg.resp.rate_hz; | ||||
DPRINTF("clock = %d(Hz)\n", rate); | DPRINTF("clock = %d(Hz)\n", rate); | ||||
return (rate); | return (rate); | ||||
} | } | ||||
static int | static int | ||||
bcm2835_cpufreq_get_turbo(struct bcm2835_cpufreq_softc *sc) | bcm2835_cpufreq_get_turbo(struct bcm2835_cpufreq_softc *sc) | ||||
{ | { | ||||
struct msg_get_turbo msg; | union msg_get_turbo_body msg; | ||||
int level; | int level; | ||||
int err; | int err; | ||||
/* | /* | ||||
* Get turbo | * Get turbo | ||||
* Tag: 0x00030009 | * Tag: 0x00030009 | ||||
* Request: | * Request: | ||||
* Length: 4 | * Length: 4 | ||||
* Value: | * Value: | ||||
* u32: id | * u32: id | ||||
* Response: | * Response: | ||||
* Length: 8 | * Length: 8 | ||||
* Value: | * Value: | ||||
* u32: id | * u32: id | ||||
* u32: level | * u32: level | ||||
*/ | */ | ||||
/* setup single tag buffer */ | /* setup single tag buffer */ | ||||
memset(&msg, 0, sizeof(msg)); | memset(&msg, 0, sizeof(msg)); | ||||
msg.hdr.buf_size = sizeof(msg); | msg.req.id = 0; | ||||
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 */ | /* call mailbox property */ | ||||
err = bcm2835_mbox_property(&msg, sizeof(msg)); | err = bcm2835_firmware_property(sc->firmware, | ||||
BCM2835_FIRMWARE_TAG_GET_TURBO, &msg, sizeof(msg)); | |||||
if (err) { | if (err) { | ||||
device_printf(sc->dev, "can't get turbo\n"); | device_printf(sc->dev, "can't get turbo\n"); | ||||
return (MSG_ERROR); | return (MSG_ERROR); | ||||
} | } | ||||
/* result 0=non-turbo, 1=turbo */ | /* result 0=non-turbo, 1=turbo */ | ||||
level = (int)msg.body.resp.level; | level = (int)msg.resp.level; | ||||
DPRINTF("level = %d\n", level); | DPRINTF("level = %d\n", level); | ||||
return (level); | return (level); | ||||
} | } | ||||
static int | static int | ||||
bcm2835_cpufreq_set_turbo(struct bcm2835_cpufreq_softc *sc, uint32_t level) | bcm2835_cpufreq_set_turbo(struct bcm2835_cpufreq_softc *sc, uint32_t level) | ||||
{ | { | ||||
struct msg_set_turbo msg; | union msg_set_turbo_body msg; | ||||
int value; | int value; | ||||
int err; | int err; | ||||
/* | /* | ||||
* Set turbo | * Set turbo | ||||
* Tag: 0x00038009 | * Tag: 0x00038009 | ||||
* Request: | * Request: | ||||
* Length: 8 | * Length: 8 | ||||
* Value: | * Value: | ||||
* u32: id | * u32: id | ||||
* u32: level | * u32: level | ||||
* Response: | * Response: | ||||
* Length: 8 | * Length: 8 | ||||
* Value: | * Value: | ||||
* u32: id | * u32: id | ||||
* u32: level | * u32: level | ||||
*/ | */ | ||||
/* replace unknown value to OFF */ | /* replace unknown value to OFF */ | ||||
if (level != BCM2835_MBOX_TURBO_ON && level != BCM2835_MBOX_TURBO_OFF) | if (level != BCM2835_FIRMWARE_TURBO_ON && | ||||
level = BCM2835_MBOX_TURBO_OFF; | level != BCM2835_FIRMWARE_TURBO_OFF) | ||||
level = BCM2835_FIRMWARE_TURBO_OFF; | |||||
/* setup single tag buffer */ | /* setup single tag buffer */ | ||||
memset(&msg, 0, sizeof(msg)); | memset(&msg, 0, sizeof(msg)); | ||||
msg.hdr.buf_size = sizeof(msg); | msg.req.id = 0; | ||||
msg.hdr.code = BCM2835_MBOX_CODE_REQ; | msg.req.level = level; | ||||
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 */ | /* call mailbox property */ | ||||
err = bcm2835_mbox_property(&msg, sizeof(msg)); | err = bcm2835_firmware_property(sc->firmware, | ||||
BCM2835_FIRMWARE_TAG_SET_TURBO, &msg, sizeof(msg)); | |||||
if (err) { | if (err) { | ||||
device_printf(sc->dev, "can't set turbo\n"); | device_printf(sc->dev, "can't set turbo\n"); | ||||
return (MSG_ERROR); | return (MSG_ERROR); | ||||
} | } | ||||
/* result 0=non-turbo, 1=turbo */ | /* result 0=non-turbo, 1=turbo */ | ||||
value = (int)msg.body.resp.level; | value = (int)msg.resp.level; | ||||
DPRINTF("level = %d\n", value); | DPRINTF("level = %d\n", value); | ||||
return (value); | return (value); | ||||
} | } | ||||
static int | static int | ||||
bcm2835_cpufreq_get_voltage(struct bcm2835_cpufreq_softc *sc, | bcm2835_cpufreq_get_voltage(struct bcm2835_cpufreq_softc *sc, | ||||
uint32_t voltage_id) | uint32_t voltage_id) | ||||
{ | { | ||||
struct msg_get_voltage msg; | union msg_get_voltage_body msg; | ||||
int value; | int value; | ||||
int err; | int err; | ||||
/* | /* | ||||
* Get voltage | * Get voltage | ||||
* Tag: 0x00030003 | * Tag: 0x00030003 | ||||
* Request: | * Request: | ||||
* Length: 4 | * Length: 4 | ||||
* Value: | * Value: | ||||
* u32: voltage id | * u32: voltage id | ||||
* Response: | * Response: | ||||
* Length: 8 | * Length: 8 | ||||
* Value: | * Value: | ||||
* u32: voltage id | * u32: voltage id | ||||
* u32: value (offset from 1.2V in units of 0.025V) | * u32: value (offset from 1.2V in units of 0.025V) | ||||
*/ | */ | ||||
/* setup single tag buffer */ | /* setup single tag buffer */ | ||||
memset(&msg, 0, sizeof(msg)); | memset(&msg, 0, sizeof(msg)); | ||||
msg.hdr.buf_size = sizeof(msg); | msg.req.voltage_id = voltage_id; | ||||
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 */ | /* call mailbox property */ | ||||
err = bcm2835_mbox_property(&msg, sizeof(msg)); | err = bcm2835_firmware_property(sc->firmware, | ||||
BCM2835_FIRMWARE_TAG_GET_VOLTAGE, &msg, sizeof(msg)); | |||||
if (err) { | if (err) { | ||||
device_printf(sc->dev, "can't get voltage\n"); | device_printf(sc->dev, "can't get voltage\n"); | ||||
return (MSG_ERROR); | return (MSG_ERROR); | ||||
} | } | ||||
/* result (offset from 1.2V) */ | /* result (offset from 1.2V) */ | ||||
value = (int)msg.body.resp.value; | value = (int)msg.resp.value; | ||||
DPRINTF("value = %d\n", value); | DPRINTF("value = %d\n", value); | ||||
return (value); | return (value); | ||||
} | } | ||||
static int | static int | ||||
bcm2835_cpufreq_get_max_voltage(struct bcm2835_cpufreq_softc *sc, | bcm2835_cpufreq_get_max_voltage(struct bcm2835_cpufreq_softc *sc, | ||||
uint32_t voltage_id) | uint32_t voltage_id) | ||||
{ | { | ||||
struct msg_get_max_voltage msg; | union msg_get_voltage_body msg; | ||||
int value; | int value; | ||||
int err; | int err; | ||||
/* | /* | ||||
* Get voltage | * Get voltage | ||||
* Tag: 0x00030005 | * Tag: 0x00030005 | ||||
* Request: | * Request: | ||||
* Length: 4 | * Length: 4 | ||||
* Value: | * Value: | ||||
* u32: voltage id | * u32: voltage id | ||||
* Response: | * Response: | ||||
* Length: 8 | * Length: 8 | ||||
* Value: | * Value: | ||||
* u32: voltage id | * u32: voltage id | ||||
* u32: value (offset from 1.2V in units of 0.025V) | * u32: value (offset from 1.2V in units of 0.025V) | ||||
*/ | */ | ||||
/* setup single tag buffer */ | /* setup single tag buffer */ | ||||
memset(&msg, 0, sizeof(msg)); | memset(&msg, 0, sizeof(msg)); | ||||
msg.hdr.buf_size = sizeof(msg); | msg.req.voltage_id = voltage_id; | ||||
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 */ | /* call mailbox property */ | ||||
err = bcm2835_mbox_property(&msg, sizeof(msg)); | err = bcm2835_firmware_property(sc->firmware, | ||||
BCM2835_FIRMWARE_TAG_GET_MAX_VOLTAGE, &msg, sizeof(msg)); | |||||
if (err) { | if (err) { | ||||
device_printf(sc->dev, "can't get max voltage\n"); | device_printf(sc->dev, "can't get max voltage\n"); | ||||
return (MSG_ERROR); | return (MSG_ERROR); | ||||
} | } | ||||
/* result (offset from 1.2V) */ | /* result (offset from 1.2V) */ | ||||
value = (int)msg.body.resp.value; | value = (int)msg.resp.value; | ||||
DPRINTF("value = %d\n", value); | DPRINTF("value = %d\n", value); | ||||
return (value); | return (value); | ||||
} | } | ||||
static int | static int | ||||
bcm2835_cpufreq_get_min_voltage(struct bcm2835_cpufreq_softc *sc, | bcm2835_cpufreq_get_min_voltage(struct bcm2835_cpufreq_softc *sc, | ||||
uint32_t voltage_id) | uint32_t voltage_id) | ||||
{ | { | ||||
struct msg_get_min_voltage msg; | union msg_get_voltage_body msg; | ||||
int value; | int value; | ||||
int err; | int err; | ||||
/* | /* | ||||
* Get voltage | * Get voltage | ||||
* Tag: 0x00030008 | * Tag: 0x00030008 | ||||
* Request: | * Request: | ||||
* Length: 4 | * Length: 4 | ||||
* Value: | * Value: | ||||
* u32: voltage id | * u32: voltage id | ||||
* Response: | * Response: | ||||
* Length: 8 | * Length: 8 | ||||
* Value: | * Value: | ||||
* u32: voltage id | * u32: voltage id | ||||
* u32: value (offset from 1.2V in units of 0.025V) | * u32: value (offset from 1.2V in units of 0.025V) | ||||
*/ | */ | ||||
/* setup single tag buffer */ | /* setup single tag buffer */ | ||||
memset(&msg, 0, sizeof(msg)); | memset(&msg, 0, sizeof(msg)); | ||||
msg.hdr.buf_size = sizeof(msg); | msg.req.voltage_id = voltage_id; | ||||
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 */ | /* call mailbox property */ | ||||
err = bcm2835_mbox_property(&msg, sizeof(msg)); | err = bcm2835_firmware_property(sc->firmware, | ||||
BCM2835_FIRMWARE_TAG_GET_MIN_VOLTAGE, &msg, sizeof(msg)); | |||||
if (err) { | if (err) { | ||||
device_printf(sc->dev, "can't get min voltage\n"); | device_printf(sc->dev, "can't get min voltage\n"); | ||||
return (MSG_ERROR); | return (MSG_ERROR); | ||||
} | } | ||||
/* result (offset from 1.2V) */ | /* result (offset from 1.2V) */ | ||||
value = (int)msg.body.resp.value; | value = (int)msg.resp.value; | ||||
DPRINTF("value = %d\n", value); | DPRINTF("value = %d\n", value); | ||||
return (value); | return (value); | ||||
} | } | ||||
static int | static int | ||||
bcm2835_cpufreq_set_voltage(struct bcm2835_cpufreq_softc *sc, | bcm2835_cpufreq_set_voltage(struct bcm2835_cpufreq_softc *sc, | ||||
uint32_t voltage_id, int32_t value) | uint32_t voltage_id, int32_t value) | ||||
{ | { | ||||
struct msg_set_voltage msg; | union msg_set_voltage_body msg; | ||||
int err; | int err; | ||||
/* | /* | ||||
* Set voltage | * Set voltage | ||||
* Tag: 0x00038003 | * Tag: 0x00038003 | ||||
* Request: | * Request: | ||||
* Length: 4 | * Length: 4 | ||||
* Value: | * Value: | ||||
Show All 14 Lines | bcm2835_cpufreq_set_voltage(struct bcm2835_cpufreq_softc *sc, | ||||
if (value > MAX_OVER_VOLTAGE || value < MIN_OVER_VOLTAGE) { | if (value > MAX_OVER_VOLTAGE || value < MIN_OVER_VOLTAGE) { | ||||
/* currently not supported */ | /* currently not supported */ | ||||
device_printf(sc->dev, "not supported voltage: %d\n", value); | device_printf(sc->dev, "not supported voltage: %d\n", value); | ||||
return (MSG_ERROR); | return (MSG_ERROR); | ||||
} | } | ||||
/* setup single tag buffer */ | /* setup single tag buffer */ | ||||
memset(&msg, 0, sizeof(msg)); | memset(&msg, 0, sizeof(msg)); | ||||
msg.hdr.buf_size = sizeof(msg); | msg.req.voltage_id = voltage_id; | ||||
msg.hdr.code = BCM2835_MBOX_CODE_REQ; | msg.req.value = (uint32_t)value; | ||||
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 */ | /* call mailbox property */ | ||||
err = bcm2835_mbox_property(&msg, sizeof(msg)); | err = bcm2835_firmware_property(sc->firmware, | ||||
BCM2835_FIRMWARE_TAG_SET_VOLTAGE, &msg, sizeof(msg)); | |||||
if (err) { | if (err) { | ||||
device_printf(sc->dev, "can't set voltage\n"); | device_printf(sc->dev, "can't set voltage\n"); | ||||
return (MSG_ERROR); | return (MSG_ERROR); | ||||
} | } | ||||
/* result (offset from 1.2V) */ | /* result (offset from 1.2V) */ | ||||
value = (int)msg.body.resp.value; | value = (int)msg.resp.value; | ||||
DPRINTF("value = %d\n", value); | DPRINTF("value = %d\n", value); | ||||
return (value); | return (value); | ||||
} | } | ||||
static int | static int | ||||
bcm2835_cpufreq_get_temperature(struct bcm2835_cpufreq_softc *sc) | bcm2835_cpufreq_get_temperature(struct bcm2835_cpufreq_softc *sc) | ||||
{ | { | ||||
struct msg_get_temperature msg; | union msg_get_temperature_body msg; | ||||
int value; | int value; | ||||
int err; | int err; | ||||
/* | /* | ||||
* Get temperature | * Get temperature | ||||
* Tag: 0x00030006 | * Tag: 0x00030006 | ||||
* Request: | * Request: | ||||
* Length: 4 | * Length: 4 | ||||
* Value: | * Value: | ||||
* u32: temperature id | * u32: temperature id | ||||
* Response: | * Response: | ||||
* Length: 8 | * Length: 8 | ||||
* Value: | * Value: | ||||
* u32: temperature id | * u32: temperature id | ||||
* u32: value | * u32: value | ||||
*/ | */ | ||||
/* setup single tag buffer */ | /* setup single tag buffer */ | ||||
memset(&msg, 0, sizeof(msg)); | memset(&msg, 0, sizeof(msg)); | ||||
msg.hdr.buf_size = sizeof(msg); | msg.req.temperature_id = 0; | ||||
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 */ | /* call mailbox property */ | ||||
err = bcm2835_mbox_property(&msg, sizeof(msg)); | err = bcm2835_firmware_property(sc->firmware, | ||||
BCM2835_FIRMWARE_TAG_GET_TEMPERATURE, &msg, sizeof(msg)); | |||||
if (err) { | if (err) { | ||||
device_printf(sc->dev, "can't get temperature\n"); | device_printf(sc->dev, "can't get temperature\n"); | ||||
return (MSG_ERROR); | return (MSG_ERROR); | ||||
} | } | ||||
/* result (temperature of degree C) */ | /* result (temperature of degree C) */ | ||||
value = (int)msg.body.resp.value; | value = (int)msg.resp.value; | ||||
DPRINTF("value = %d\n", value); | DPRINTF("value = %d\n", value); | ||||
return (value); | return (value); | ||||
} | } | ||||
static int | static int | ||||
sysctl_bcm2835_cpufreq_arm_freq(SYSCTL_HANDLER_ARGS) | sysctl_bcm2835_cpufreq_arm_freq(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct bcm2835_cpufreq_softc *sc = arg1; | struct bcm2835_cpufreq_softc *sc = arg1; | ||||
int val; | int val; | ||||
int err; | int err; | ||||
/* get realtime value */ | /* get realtime value */ | ||||
VC_LOCK(sc); | VC_LOCK(sc); | ||||
val = bcm2835_cpufreq_get_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_ARM); | val = bcm2835_cpufreq_get_clock_rate(sc, BCM2835_FIRMWARE_CLOCK_ID_ARM); | ||||
VC_UNLOCK(sc); | VC_UNLOCK(sc); | ||||
if (val == MSG_ERROR) | if (val == MSG_ERROR) | ||||
return (EIO); | return (EIO); | ||||
err = sysctl_handle_int(oidp, &val, 0, req); | err = sysctl_handle_int(oidp, &val, 0, req); | ||||
if (err || !req->newptr) /* error || read request */ | if (err || !req->newptr) /* error || read request */ | ||||
return (err); | return (err); | ||||
/* write request */ | /* write request */ | ||||
VC_LOCK(sc); | VC_LOCK(sc); | ||||
err = bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_ARM, | err = bcm2835_cpufreq_set_clock_rate(sc, BCM2835_FIRMWARE_CLOCK_ID_ARM, | ||||
val); | val); | ||||
VC_UNLOCK(sc); | VC_UNLOCK(sc); | ||||
if (err == MSG_ERROR) { | if (err == MSG_ERROR) { | ||||
device_printf(sc->dev, "set clock arm_freq error\n"); | device_printf(sc->dev, "set clock arm_freq error\n"); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
DELAY(TRANSITION_LATENCY); | DELAY(TRANSITION_LATENCY); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
sysctl_bcm2835_cpufreq_core_freq(SYSCTL_HANDLER_ARGS) | sysctl_bcm2835_cpufreq_core_freq(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct bcm2835_cpufreq_softc *sc = arg1; | struct bcm2835_cpufreq_softc *sc = arg1; | ||||
int val; | int val; | ||||
int err; | int err; | ||||
/* get realtime value */ | /* get realtime value */ | ||||
VC_LOCK(sc); | VC_LOCK(sc); | ||||
val = bcm2835_cpufreq_get_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_CORE); | val = bcm2835_cpufreq_get_clock_rate(sc, | ||||
BCM2835_FIRMWARE_CLOCK_ID_CORE); | |||||
VC_UNLOCK(sc); | VC_UNLOCK(sc); | ||||
if (val == MSG_ERROR) | if (val == MSG_ERROR) | ||||
return (EIO); | return (EIO); | ||||
err = sysctl_handle_int(oidp, &val, 0, req); | err = sysctl_handle_int(oidp, &val, 0, req); | ||||
if (err || !req->newptr) /* error || read request */ | if (err || !req->newptr) /* error || read request */ | ||||
return (err); | return (err); | ||||
/* write request */ | /* write request */ | ||||
VC_LOCK(sc); | VC_LOCK(sc); | ||||
err = bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_CORE, | err = bcm2835_cpufreq_set_clock_rate(sc, BCM2835_FIRMWARE_CLOCK_ID_CORE, | ||||
val); | val); | ||||
if (err == MSG_ERROR) { | if (err == MSG_ERROR) { | ||||
VC_UNLOCK(sc); | VC_UNLOCK(sc); | ||||
device_printf(sc->dev, "set clock core_freq error\n"); | device_printf(sc->dev, "set clock core_freq error\n"); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
VC_UNLOCK(sc); | VC_UNLOCK(sc); | ||||
DELAY(TRANSITION_LATENCY); | DELAY(TRANSITION_LATENCY); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
sysctl_bcm2835_cpufreq_sdram_freq(SYSCTL_HANDLER_ARGS) | sysctl_bcm2835_cpufreq_sdram_freq(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct bcm2835_cpufreq_softc *sc = arg1; | struct bcm2835_cpufreq_softc *sc = arg1; | ||||
int val; | int val; | ||||
int err; | int err; | ||||
/* get realtime value */ | /* get realtime value */ | ||||
VC_LOCK(sc); | VC_LOCK(sc); | ||||
val = bcm2835_cpufreq_get_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_SDRAM); | val = bcm2835_cpufreq_get_clock_rate(sc, | ||||
BCM2835_FIRMWARE_CLOCK_ID_SDRAM); | |||||
VC_UNLOCK(sc); | VC_UNLOCK(sc); | ||||
if (val == MSG_ERROR) | if (val == MSG_ERROR) | ||||
return (EIO); | return (EIO); | ||||
err = sysctl_handle_int(oidp, &val, 0, req); | err = sysctl_handle_int(oidp, &val, 0, req); | ||||
if (err || !req->newptr) /* error || read request */ | if (err || !req->newptr) /* error || read request */ | ||||
return (err); | return (err); | ||||
/* write request */ | /* write request */ | ||||
VC_LOCK(sc); | VC_LOCK(sc); | ||||
err = bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_SDRAM, | err = bcm2835_cpufreq_set_clock_rate(sc, | ||||
val); | BCM2835_FIRMWARE_CLOCK_ID_SDRAM, val); | ||||
VC_UNLOCK(sc); | VC_UNLOCK(sc); | ||||
if (err == MSG_ERROR) { | if (err == MSG_ERROR) { | ||||
device_printf(sc->dev, "set clock sdram_freq error\n"); | device_printf(sc->dev, "set clock sdram_freq error\n"); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
DELAY(TRANSITION_LATENCY); | DELAY(TRANSITION_LATENCY); | ||||
return (0); | return (0); | ||||
Show All 14 Lines | if (val == MSG_ERROR) | ||||
return (EIO); | return (EIO); | ||||
err = sysctl_handle_int(oidp, &val, 0, req); | err = sysctl_handle_int(oidp, &val, 0, req); | ||||
if (err || !req->newptr) /* error || read request */ | if (err || !req->newptr) /* error || read request */ | ||||
return (err); | return (err); | ||||
/* write request */ | /* write request */ | ||||
if (val > 0) | if (val > 0) | ||||
sc->turbo_mode = BCM2835_MBOX_TURBO_ON; | sc->turbo_mode = BCM2835_FIRMWARE_TURBO_ON; | ||||
else | else | ||||
sc->turbo_mode = BCM2835_MBOX_TURBO_OFF; | sc->turbo_mode = BCM2835_FIRMWARE_TURBO_OFF; | ||||
VC_LOCK(sc); | VC_LOCK(sc); | ||||
err = bcm2835_cpufreq_set_turbo(sc, sc->turbo_mode); | err = bcm2835_cpufreq_set_turbo(sc, sc->turbo_mode); | ||||
VC_UNLOCK(sc); | VC_UNLOCK(sc); | ||||
if (err == MSG_ERROR) { | if (err == MSG_ERROR) { | ||||
device_printf(sc->dev, "set turbo error\n"); | device_printf(sc->dev, "set turbo error\n"); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
DELAY(TRANSITION_LATENCY); | DELAY(TRANSITION_LATENCY); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
sysctl_bcm2835_cpufreq_voltage_core(SYSCTL_HANDLER_ARGS) | sysctl_bcm2835_cpufreq_voltage_core(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct bcm2835_cpufreq_softc *sc = arg1; | struct bcm2835_cpufreq_softc *sc = arg1; | ||||
int val; | int val; | ||||
int err; | int err; | ||||
/* get realtime value */ | /* get realtime value */ | ||||
VC_LOCK(sc); | VC_LOCK(sc); | ||||
val = bcm2835_cpufreq_get_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_CORE); | val = bcm2835_cpufreq_get_voltage(sc, BCM2835_FIRMWARE_VOLTAGE_ID_CORE); | ||||
VC_UNLOCK(sc); | VC_UNLOCK(sc); | ||||
if (val == MSG_ERROR) | if (val == MSG_ERROR) | ||||
return (EIO); | return (EIO); | ||||
err = sysctl_handle_int(oidp, &val, 0, req); | err = sysctl_handle_int(oidp, &val, 0, req); | ||||
if (err || !req->newptr) /* error || read request */ | if (err || !req->newptr) /* error || read request */ | ||||
return (err); | return (err); | ||||
/* write request */ | /* write request */ | ||||
if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE) | if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE) | ||||
return (EINVAL); | return (EINVAL); | ||||
sc->voltage_core = val; | sc->voltage_core = val; | ||||
VC_LOCK(sc); | VC_LOCK(sc); | ||||
err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_CORE, | err = bcm2835_cpufreq_set_voltage(sc, BCM2835_FIRMWARE_VOLTAGE_ID_CORE, | ||||
sc->voltage_core); | sc->voltage_core); | ||||
VC_UNLOCK(sc); | VC_UNLOCK(sc); | ||||
if (err == MSG_ERROR) { | if (err == MSG_ERROR) { | ||||
device_printf(sc->dev, "set voltage core error\n"); | device_printf(sc->dev, "set voltage core error\n"); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
DELAY(TRANSITION_LATENCY); | DELAY(TRANSITION_LATENCY); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
sysctl_bcm2835_cpufreq_voltage_sdram_c(SYSCTL_HANDLER_ARGS) | sysctl_bcm2835_cpufreq_voltage_sdram_c(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct bcm2835_cpufreq_softc *sc = arg1; | struct bcm2835_cpufreq_softc *sc = arg1; | ||||
int val; | int val; | ||||
int err; | int err; | ||||
/* get realtime value */ | /* get realtime value */ | ||||
VC_LOCK(sc); | VC_LOCK(sc); | ||||
val = bcm2835_cpufreq_get_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_C); | val = bcm2835_cpufreq_get_voltage(sc, | ||||
BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_C); | |||||
VC_UNLOCK(sc); | VC_UNLOCK(sc); | ||||
if (val == MSG_ERROR) | if (val == MSG_ERROR) | ||||
return (EIO); | return (EIO); | ||||
err = sysctl_handle_int(oidp, &val, 0, req); | err = sysctl_handle_int(oidp, &val, 0, req); | ||||
if (err || !req->newptr) /* error || read request */ | if (err || !req->newptr) /* error || read request */ | ||||
return (err); | return (err); | ||||
/* write request */ | /* write request */ | ||||
if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE) | if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE) | ||||
return (EINVAL); | return (EINVAL); | ||||
sc->voltage_sdram_c = val; | sc->voltage_sdram_c = val; | ||||
VC_LOCK(sc); | VC_LOCK(sc); | ||||
err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_C, | err = bcm2835_cpufreq_set_voltage(sc, | ||||
BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_C, | |||||
sc->voltage_sdram_c); | sc->voltage_sdram_c); | ||||
VC_UNLOCK(sc); | VC_UNLOCK(sc); | ||||
if (err == MSG_ERROR) { | if (err == MSG_ERROR) { | ||||
device_printf(sc->dev, "set voltage sdram_c error\n"); | device_printf(sc->dev, "set voltage sdram_c error\n"); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
DELAY(TRANSITION_LATENCY); | DELAY(TRANSITION_LATENCY); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
sysctl_bcm2835_cpufreq_voltage_sdram_i(SYSCTL_HANDLER_ARGS) | sysctl_bcm2835_cpufreq_voltage_sdram_i(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct bcm2835_cpufreq_softc *sc = arg1; | struct bcm2835_cpufreq_softc *sc = arg1; | ||||
int val; | int val; | ||||
int err; | int err; | ||||
/* get realtime value */ | /* get realtime value */ | ||||
VC_LOCK(sc); | VC_LOCK(sc); | ||||
val = bcm2835_cpufreq_get_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_I); | val = bcm2835_cpufreq_get_voltage(sc, | ||||
BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_I); | |||||
VC_UNLOCK(sc); | VC_UNLOCK(sc); | ||||
if (val == MSG_ERROR) | if (val == MSG_ERROR) | ||||
return (EIO); | return (EIO); | ||||
err = sysctl_handle_int(oidp, &val, 0, req); | err = sysctl_handle_int(oidp, &val, 0, req); | ||||
if (err || !req->newptr) /* error || read request */ | if (err || !req->newptr) /* error || read request */ | ||||
return (err); | return (err); | ||||
/* write request */ | /* write request */ | ||||
if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE) | if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE) | ||||
return (EINVAL); | return (EINVAL); | ||||
sc->voltage_sdram_i = val; | sc->voltage_sdram_i = val; | ||||
VC_LOCK(sc); | VC_LOCK(sc); | ||||
err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_I, | err = bcm2835_cpufreq_set_voltage(sc, | ||||
sc->voltage_sdram_i); | BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_I, sc->voltage_sdram_i); | ||||
VC_UNLOCK(sc); | VC_UNLOCK(sc); | ||||
if (err == MSG_ERROR) { | if (err == MSG_ERROR) { | ||||
device_printf(sc->dev, "set voltage sdram_i error\n"); | device_printf(sc->dev, "set voltage sdram_i error\n"); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
DELAY(TRANSITION_LATENCY); | DELAY(TRANSITION_LATENCY); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
sysctl_bcm2835_cpufreq_voltage_sdram_p(SYSCTL_HANDLER_ARGS) | sysctl_bcm2835_cpufreq_voltage_sdram_p(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct bcm2835_cpufreq_softc *sc = arg1; | struct bcm2835_cpufreq_softc *sc = arg1; | ||||
int val; | int val; | ||||
int err; | int err; | ||||
/* get realtime value */ | /* get realtime value */ | ||||
VC_LOCK(sc); | VC_LOCK(sc); | ||||
val = bcm2835_cpufreq_get_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_P); | val = bcm2835_cpufreq_get_voltage(sc, | ||||
BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_P); | |||||
VC_UNLOCK(sc); | VC_UNLOCK(sc); | ||||
if (val == MSG_ERROR) | if (val == MSG_ERROR) | ||||
return (EIO); | return (EIO); | ||||
err = sysctl_handle_int(oidp, &val, 0, req); | err = sysctl_handle_int(oidp, &val, 0, req); | ||||
if (err || !req->newptr) /* error || read request */ | if (err || !req->newptr) /* error || read request */ | ||||
return (err); | return (err); | ||||
/* write request */ | /* write request */ | ||||
if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE) | if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE) | ||||
return (EINVAL); | return (EINVAL); | ||||
sc->voltage_sdram_p = val; | sc->voltage_sdram_p = val; | ||||
VC_LOCK(sc); | VC_LOCK(sc); | ||||
err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_P, | err = bcm2835_cpufreq_set_voltage(sc, | ||||
sc->voltage_sdram_p); | BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_P, sc->voltage_sdram_p); | ||||
VC_UNLOCK(sc); | VC_UNLOCK(sc); | ||||
if (err == MSG_ERROR) { | if (err == MSG_ERROR) { | ||||
device_printf(sc->dev, "set voltage sdram_p error\n"); | device_printf(sc->dev, "set voltage sdram_p error\n"); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
DELAY(TRANSITION_LATENCY); | DELAY(TRANSITION_LATENCY); | ||||
return (0); | return (0); | ||||
Show All 15 Lines | if (err) | ||||
return (err); | return (err); | ||||
/* write request */ | /* write request */ | ||||
if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE) | if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE) | ||||
return (EINVAL); | return (EINVAL); | ||||
sc->voltage_sdram = val; | sc->voltage_sdram = val; | ||||
VC_LOCK(sc); | VC_LOCK(sc); | ||||
err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_C, | err = bcm2835_cpufreq_set_voltage(sc, | ||||
val); | BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_C, val); | ||||
if (err == MSG_ERROR) { | if (err == MSG_ERROR) { | ||||
VC_UNLOCK(sc); | VC_UNLOCK(sc); | ||||
device_printf(sc->dev, "set voltage sdram_c error\n"); | device_printf(sc->dev, "set voltage sdram_c error\n"); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_I, | err = bcm2835_cpufreq_set_voltage(sc, | ||||
val); | BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_I, val); | ||||
if (err == MSG_ERROR) { | if (err == MSG_ERROR) { | ||||
VC_UNLOCK(sc); | VC_UNLOCK(sc); | ||||
device_printf(sc->dev, "set voltage sdram_i error\n"); | device_printf(sc->dev, "set voltage sdram_i error\n"); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_P, | err = bcm2835_cpufreq_set_voltage(sc, | ||||
val); | BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_P, val); | ||||
if (err == MSG_ERROR) { | if (err == MSG_ERROR) { | ||||
VC_UNLOCK(sc); | VC_UNLOCK(sc); | ||||
device_printf(sc->dev, "set voltage sdram_p error\n"); | device_printf(sc->dev, "set voltage sdram_p error\n"); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
VC_UNLOCK(sc); | VC_UNLOCK(sc); | ||||
DELAY(TRANSITION_LATENCY); | DELAY(TRANSITION_LATENCY); | ||||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | bcm2835_cpufreq_init(void *arg) | ||||
int max_voltage_sdram_i, min_voltage_sdram_i; | int max_voltage_sdram_i, min_voltage_sdram_i; | ||||
int max_voltage_sdram_p, min_voltage_sdram_p; | int max_voltage_sdram_p, min_voltage_sdram_p; | ||||
int turbo, temperature; | int turbo, temperature; | ||||
VC_LOCK(sc); | VC_LOCK(sc); | ||||
/* current clock */ | /* current clock */ | ||||
arm_freq = bcm2835_cpufreq_get_clock_rate(sc, | arm_freq = bcm2835_cpufreq_get_clock_rate(sc, | ||||
BCM2835_MBOX_CLOCK_ID_ARM); | BCM2835_FIRMWARE_CLOCK_ID_ARM); | ||||
core_freq = bcm2835_cpufreq_get_clock_rate(sc, | core_freq = bcm2835_cpufreq_get_clock_rate(sc, | ||||
BCM2835_MBOX_CLOCK_ID_CORE); | BCM2835_FIRMWARE_CLOCK_ID_CORE); | ||||
sdram_freq = bcm2835_cpufreq_get_clock_rate(sc, | sdram_freq = bcm2835_cpufreq_get_clock_rate(sc, | ||||
BCM2835_MBOX_CLOCK_ID_SDRAM); | BCM2835_FIRMWARE_CLOCK_ID_SDRAM); | ||||
/* max/min clock */ | /* max/min clock */ | ||||
arm_max_freq = bcm2835_cpufreq_get_max_clock_rate(sc, | arm_max_freq = bcm2835_cpufreq_get_max_clock_rate(sc, | ||||
BCM2835_MBOX_CLOCK_ID_ARM); | BCM2835_FIRMWARE_CLOCK_ID_ARM); | ||||
arm_min_freq = bcm2835_cpufreq_get_min_clock_rate(sc, | arm_min_freq = bcm2835_cpufreq_get_min_clock_rate(sc, | ||||
BCM2835_MBOX_CLOCK_ID_ARM); | BCM2835_FIRMWARE_CLOCK_ID_ARM); | ||||
core_max_freq = bcm2835_cpufreq_get_max_clock_rate(sc, | core_max_freq = bcm2835_cpufreq_get_max_clock_rate(sc, | ||||
BCM2835_MBOX_CLOCK_ID_CORE); | BCM2835_FIRMWARE_CLOCK_ID_CORE); | ||||
core_min_freq = bcm2835_cpufreq_get_min_clock_rate(sc, | core_min_freq = bcm2835_cpufreq_get_min_clock_rate(sc, | ||||
BCM2835_MBOX_CLOCK_ID_CORE); | BCM2835_FIRMWARE_CLOCK_ID_CORE); | ||||
sdram_max_freq = bcm2835_cpufreq_get_max_clock_rate(sc, | sdram_max_freq = bcm2835_cpufreq_get_max_clock_rate(sc, | ||||
BCM2835_MBOX_CLOCK_ID_SDRAM); | BCM2835_FIRMWARE_CLOCK_ID_SDRAM); | ||||
sdram_min_freq = bcm2835_cpufreq_get_min_clock_rate(sc, | sdram_min_freq = bcm2835_cpufreq_get_min_clock_rate(sc, | ||||
BCM2835_MBOX_CLOCK_ID_SDRAM); | BCM2835_FIRMWARE_CLOCK_ID_SDRAM); | ||||
/* turbo mode */ | /* turbo mode */ | ||||
turbo = bcm2835_cpufreq_get_turbo(sc); | turbo = bcm2835_cpufreq_get_turbo(sc); | ||||
if (turbo > 0) | if (turbo > 0) | ||||
sc->turbo_mode = BCM2835_MBOX_TURBO_ON; | sc->turbo_mode = BCM2835_FIRMWARE_TURBO_ON; | ||||
else | else | ||||
sc->turbo_mode = BCM2835_MBOX_TURBO_OFF; | sc->turbo_mode = BCM2835_FIRMWARE_TURBO_OFF; | ||||
/* voltage */ | /* voltage */ | ||||
voltage_core = bcm2835_cpufreq_get_voltage(sc, | voltage_core = bcm2835_cpufreq_get_voltage(sc, | ||||
BCM2835_MBOX_VOLTAGE_ID_CORE); | BCM2835_FIRMWARE_VOLTAGE_ID_CORE); | ||||
voltage_sdram_c = bcm2835_cpufreq_get_voltage(sc, | voltage_sdram_c = bcm2835_cpufreq_get_voltage(sc, | ||||
BCM2835_MBOX_VOLTAGE_ID_SDRAM_C); | BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_C); | ||||
voltage_sdram_i = bcm2835_cpufreq_get_voltage(sc, | voltage_sdram_i = bcm2835_cpufreq_get_voltage(sc, | ||||
BCM2835_MBOX_VOLTAGE_ID_SDRAM_I); | BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_I); | ||||
voltage_sdram_p = bcm2835_cpufreq_get_voltage(sc, | voltage_sdram_p = bcm2835_cpufreq_get_voltage(sc, | ||||
BCM2835_MBOX_VOLTAGE_ID_SDRAM_P); | BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_P); | ||||
/* current values (offset from 1.2V) */ | /* current values (offset from 1.2V) */ | ||||
sc->voltage_core = voltage_core; | sc->voltage_core = voltage_core; | ||||
sc->voltage_sdram = voltage_sdram_c; | sc->voltage_sdram = voltage_sdram_c; | ||||
sc->voltage_sdram_c = voltage_sdram_c; | sc->voltage_sdram_c = voltage_sdram_c; | ||||
sc->voltage_sdram_i = voltage_sdram_i; | sc->voltage_sdram_i = voltage_sdram_i; | ||||
sc->voltage_sdram_p = voltage_sdram_p; | sc->voltage_sdram_p = voltage_sdram_p; | ||||
/* max/min voltage */ | /* max/min voltage */ | ||||
max_voltage_core = bcm2835_cpufreq_get_max_voltage(sc, | max_voltage_core = bcm2835_cpufreq_get_max_voltage(sc, | ||||
BCM2835_MBOX_VOLTAGE_ID_CORE); | BCM2835_FIRMWARE_VOLTAGE_ID_CORE); | ||||
min_voltage_core = bcm2835_cpufreq_get_min_voltage(sc, | min_voltage_core = bcm2835_cpufreq_get_min_voltage(sc, | ||||
BCM2835_MBOX_VOLTAGE_ID_CORE); | BCM2835_FIRMWARE_VOLTAGE_ID_CORE); | ||||
max_voltage_sdram_c = bcm2835_cpufreq_get_max_voltage(sc, | max_voltage_sdram_c = bcm2835_cpufreq_get_max_voltage(sc, | ||||
BCM2835_MBOX_VOLTAGE_ID_SDRAM_C); | BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_C); | ||||
max_voltage_sdram_i = bcm2835_cpufreq_get_max_voltage(sc, | max_voltage_sdram_i = bcm2835_cpufreq_get_max_voltage(sc, | ||||
BCM2835_MBOX_VOLTAGE_ID_SDRAM_I); | BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_I); | ||||
max_voltage_sdram_p = bcm2835_cpufreq_get_max_voltage(sc, | max_voltage_sdram_p = bcm2835_cpufreq_get_max_voltage(sc, | ||||
BCM2835_MBOX_VOLTAGE_ID_SDRAM_P); | BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_P); | ||||
min_voltage_sdram_c = bcm2835_cpufreq_get_min_voltage(sc, | min_voltage_sdram_c = bcm2835_cpufreq_get_min_voltage(sc, | ||||
BCM2835_MBOX_VOLTAGE_ID_SDRAM_C); | BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_C); | ||||
min_voltage_sdram_i = bcm2835_cpufreq_get_min_voltage(sc, | min_voltage_sdram_i = bcm2835_cpufreq_get_min_voltage(sc, | ||||
BCM2835_MBOX_VOLTAGE_ID_SDRAM_I); | BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_I); | ||||
min_voltage_sdram_p = bcm2835_cpufreq_get_min_voltage(sc, | min_voltage_sdram_p = bcm2835_cpufreq_get_min_voltage(sc, | ||||
BCM2835_MBOX_VOLTAGE_ID_SDRAM_P); | BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_P); | ||||
/* temperature */ | /* temperature */ | ||||
temperature = bcm2835_cpufreq_get_temperature(sc); | temperature = bcm2835_cpufreq_get_temperature(sc); | ||||
/* show result */ | /* show result */ | ||||
if (cpufreq_verbose || bootverbose) { | if (cpufreq_verbose || bootverbose) { | ||||
device_printf(sc->dev, "Boot settings:\n"); | device_printf(sc->dev, "Boot settings:\n"); | ||||
device_printf(sc->dev, | device_printf(sc->dev, | ||||
"current ARM %dMHz, Core %dMHz, SDRAM %dMHz, Turbo %s\n", | "current ARM %dMHz, Core %dMHz, SDRAM %dMHz, Turbo %s\n", | ||||
HZ2MHZ(arm_freq), HZ2MHZ(core_freq), HZ2MHZ(sdram_freq), | HZ2MHZ(arm_freq), HZ2MHZ(core_freq), HZ2MHZ(sdram_freq), | ||||
(sc->turbo_mode == BCM2835_MBOX_TURBO_ON) ? "ON" : "OFF"); | (sc->turbo_mode == BCM2835_FIRMWARE_TURBO_ON) ? "ON":"OFF"); | ||||
device_printf(sc->dev, | device_printf(sc->dev, | ||||
"max/min ARM %d/%dMHz, Core %d/%dMHz, SDRAM %d/%dMHz\n", | "max/min ARM %d/%dMHz, Core %d/%dMHz, SDRAM %d/%dMHz\n", | ||||
HZ2MHZ(arm_max_freq), HZ2MHZ(arm_min_freq), | HZ2MHZ(arm_max_freq), HZ2MHZ(arm_min_freq), | ||||
HZ2MHZ(core_max_freq), HZ2MHZ(core_min_freq), | HZ2MHZ(core_max_freq), HZ2MHZ(core_min_freq), | ||||
HZ2MHZ(sdram_max_freq), HZ2MHZ(sdram_min_freq)); | HZ2MHZ(sdram_max_freq), HZ2MHZ(sdram_min_freq)); | ||||
device_printf(sc->dev, | device_printf(sc->dev, | ||||
Show All 17 Lines | if (cpufreq_verbose || bootverbose) { | ||||
device_printf(sc->dev, | device_printf(sc->dev, | ||||
"Temperature %d.%dC\n", (temperature / 1000), | "Temperature %d.%dC\n", (temperature / 1000), | ||||
(temperature % 1000) / 100); | (temperature % 1000) / 100); | ||||
} else { /* !cpufreq_verbose && !bootverbose */ | } else { /* !cpufreq_verbose && !bootverbose */ | ||||
device_printf(sc->dev, | device_printf(sc->dev, | ||||
"ARM %dMHz, Core %dMHz, SDRAM %dMHz, Turbo %s\n", | "ARM %dMHz, Core %dMHz, SDRAM %dMHz, Turbo %s\n", | ||||
HZ2MHZ(arm_freq), HZ2MHZ(core_freq), HZ2MHZ(sdram_freq), | HZ2MHZ(arm_freq), HZ2MHZ(core_freq), HZ2MHZ(sdram_freq), | ||||
(sc->turbo_mode == BCM2835_MBOX_TURBO_ON) ? "ON" : "OFF"); | (sc->turbo_mode == BCM2835_FIRMWARE_TURBO_ON) ? "ON":"OFF"); | ||||
} | } | ||||
/* keep in softc (MHz/mV) */ | /* keep in softc (MHz/mV) */ | ||||
sc->arm_max_freq = HZ2MHZ(arm_max_freq); | sc->arm_max_freq = HZ2MHZ(arm_max_freq); | ||||
sc->arm_min_freq = HZ2MHZ(arm_min_freq); | sc->arm_min_freq = HZ2MHZ(arm_min_freq); | ||||
sc->core_max_freq = HZ2MHZ(core_max_freq); | sc->core_max_freq = HZ2MHZ(core_max_freq); | ||||
sc->core_min_freq = HZ2MHZ(core_min_freq); | sc->core_min_freq = HZ2MHZ(core_min_freq); | ||||
sc->sdram_max_freq = HZ2MHZ(sdram_max_freq); | sc->sdram_max_freq = HZ2MHZ(sdram_max_freq); | ||||
sc->sdram_min_freq = HZ2MHZ(sdram_min_freq); | sc->sdram_min_freq = HZ2MHZ(sdram_min_freq); | ||||
sc->max_voltage_core = OFFSET2MVOLT(max_voltage_core); | sc->max_voltage_core = OFFSET2MVOLT(max_voltage_core); | ||||
sc->min_voltage_core = OFFSET2MVOLT(min_voltage_core); | sc->min_voltage_core = OFFSET2MVOLT(min_voltage_core); | ||||
/* if turbo is on, set to max values */ | /* if turbo is on, set to max values */ | ||||
if (sc->turbo_mode == BCM2835_MBOX_TURBO_ON) { | if (sc->turbo_mode == BCM2835_FIRMWARE_TURBO_ON) { | ||||
bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_ARM, | bcm2835_cpufreq_set_clock_rate(sc, | ||||
arm_max_freq); | BCM2835_FIRMWARE_CLOCK_ID_ARM, arm_max_freq); | ||||
DELAY(TRANSITION_LATENCY); | DELAY(TRANSITION_LATENCY); | ||||
bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_CORE, | bcm2835_cpufreq_set_clock_rate(sc, | ||||
core_max_freq); | BCM2835_FIRMWARE_CLOCK_ID_CORE, core_max_freq); | ||||
DELAY(TRANSITION_LATENCY); | DELAY(TRANSITION_LATENCY); | ||||
bcm2835_cpufreq_set_clock_rate(sc, | bcm2835_cpufreq_set_clock_rate(sc, | ||||
BCM2835_MBOX_CLOCK_ID_SDRAM, sdram_max_freq); | BCM2835_FIRMWARE_CLOCK_ID_SDRAM, sdram_max_freq); | ||||
DELAY(TRANSITION_LATENCY); | DELAY(TRANSITION_LATENCY); | ||||
} else { | } else { | ||||
bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_ARM, | bcm2835_cpufreq_set_clock_rate(sc, | ||||
arm_min_freq); | BCM2835_FIRMWARE_CLOCK_ID_ARM, arm_min_freq); | ||||
DELAY(TRANSITION_LATENCY); | DELAY(TRANSITION_LATENCY); | ||||
bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_CORE, | bcm2835_cpufreq_set_clock_rate(sc, | ||||
core_min_freq); | BCM2835_FIRMWARE_CLOCK_ID_CORE, core_min_freq); | ||||
DELAY(TRANSITION_LATENCY); | DELAY(TRANSITION_LATENCY); | ||||
bcm2835_cpufreq_set_clock_rate(sc, | bcm2835_cpufreq_set_clock_rate(sc, | ||||
BCM2835_MBOX_CLOCK_ID_SDRAM, sdram_min_freq); | BCM2835_FIRMWARE_CLOCK_ID_SDRAM, sdram_min_freq); | ||||
DELAY(TRANSITION_LATENCY); | DELAY(TRANSITION_LATENCY); | ||||
} | } | ||||
VC_UNLOCK(sc); | VC_UNLOCK(sc); | ||||
/* add human readable temperature to dev.cpu node */ | /* add human readable temperature to dev.cpu node */ | ||||
cpu = device_get_parent(sc->dev); | cpu = device_get_parent(sc->dev); | ||||
if (cpu != NULL) { | if (cpu != NULL) { | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | |||||
bcm2835_cpufreq_attach(device_t dev) | bcm2835_cpufreq_attach(device_t dev) | ||||
{ | { | ||||
struct bcm2835_cpufreq_softc *sc; | struct bcm2835_cpufreq_softc *sc; | ||||
struct sysctl_oid *oid; | struct sysctl_oid *oid; | ||||
/* set self dev */ | /* set self dev */ | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
sc->dev = dev; | sc->dev = dev; | ||||
sc->firmware = devclass_get_device( | |||||
devclass_find("bcm2835_firmware"), 0); | |||||
if (sc->firmware == NULL) { | |||||
device_printf(dev, "Unable to find firmware device\n"); | |||||
return (ENXIO); | |||||
} | |||||
/* initial values */ | /* initial values */ | ||||
sc->arm_max_freq = -1; | sc->arm_max_freq = -1; | ||||
sc->arm_min_freq = -1; | sc->arm_min_freq = -1; | ||||
sc->core_max_freq = -1; | sc->core_max_freq = -1; | ||||
sc->core_min_freq = -1; | sc->core_min_freq = -1; | ||||
sc->sdram_max_freq = -1; | sc->sdram_max_freq = -1; | ||||
sc->sdram_min_freq = -1; | sc->sdram_min_freq = -1; | ||||
▲ Show 20 Lines • Show All 117 Lines • ▼ Show 20 Lines | #endif | ||||
rate_hz = (uint32_t)MHZ2HZ(cf->freq); | rate_hz = (uint32_t)MHZ2HZ(cf->freq); | ||||
rem = rate_hz % HZSTEP; | rem = rate_hz % HZSTEP; | ||||
rate_hz -= rem; | rate_hz -= rem; | ||||
if (rate_hz == 0) | if (rate_hz == 0) | ||||
return (EINVAL); | return (EINVAL); | ||||
/* adjust min freq */ | /* adjust min freq */ | ||||
min_freq = sc->arm_min_freq; | min_freq = sc->arm_min_freq; | ||||
if (sc->turbo_mode != BCM2835_MBOX_TURBO_ON) | if (sc->turbo_mode != BCM2835_FIRMWARE_TURBO_ON) | ||||
if (min_freq > cpufreq_lowest_freq) | if (min_freq > cpufreq_lowest_freq) | ||||
min_freq = cpufreq_lowest_freq; | min_freq = cpufreq_lowest_freq; | ||||
if (rate_hz < MHZ2HZ(min_freq) || rate_hz > MHZ2HZ(sc->arm_max_freq)) | if (rate_hz < MHZ2HZ(min_freq) || rate_hz > MHZ2HZ(sc->arm_max_freq)) | ||||
return (EINVAL); | return (EINVAL); | ||||
/* set new value and verify it */ | /* set new value and verify it */ | ||||
VC_LOCK(sc); | VC_LOCK(sc); | ||||
#ifdef DEBUG | #ifdef DEBUG | ||||
cur_freq = bcm2835_cpufreq_get_clock_rate(sc, | cur_freq = bcm2835_cpufreq_get_clock_rate(sc, | ||||
BCM2835_MBOX_CLOCK_ID_ARM); | BCM2835_FIRMWARE_CLOCK_ID_ARM); | ||||
#endif | #endif | ||||
resp_freq = bcm2835_cpufreq_set_clock_rate(sc, | resp_freq = bcm2835_cpufreq_set_clock_rate(sc, | ||||
BCM2835_MBOX_CLOCK_ID_ARM, rate_hz); | BCM2835_FIRMWARE_CLOCK_ID_ARM, rate_hz); | ||||
DELAY(TRANSITION_LATENCY); | DELAY(TRANSITION_LATENCY); | ||||
arm_freq = bcm2835_cpufreq_get_clock_rate(sc, | arm_freq = bcm2835_cpufreq_get_clock_rate(sc, | ||||
BCM2835_MBOX_CLOCK_ID_ARM); | BCM2835_FIRMWARE_CLOCK_ID_ARM); | ||||
/* | /* | ||||
* if non-turbo and lower than or equal min_freq, | * if non-turbo and lower than or equal min_freq, | ||||
* clock down core and sdram to default first. | * clock down core and sdram to default first. | ||||
*/ | */ | ||||
if (sc->turbo_mode != BCM2835_MBOX_TURBO_ON) { | if (sc->turbo_mode != BCM2835_FIRMWARE_TURBO_ON) { | ||||
core_freq = bcm2835_cpufreq_get_clock_rate(sc, | core_freq = bcm2835_cpufreq_get_clock_rate(sc, | ||||
BCM2835_MBOX_CLOCK_ID_CORE); | BCM2835_FIRMWARE_CLOCK_ID_CORE); | ||||
if (rate_hz > MHZ2HZ(sc->arm_min_freq)) { | if (rate_hz > MHZ2HZ(sc->arm_min_freq)) { | ||||
bcm2835_cpufreq_set_clock_rate(sc, | bcm2835_cpufreq_set_clock_rate(sc, | ||||
BCM2835_MBOX_CLOCK_ID_CORE, | BCM2835_FIRMWARE_CLOCK_ID_CORE, | ||||
MHZ2HZ(sc->core_max_freq)); | MHZ2HZ(sc->core_max_freq)); | ||||
DELAY(TRANSITION_LATENCY); | DELAY(TRANSITION_LATENCY); | ||||
bcm2835_cpufreq_set_clock_rate(sc, | bcm2835_cpufreq_set_clock_rate(sc, | ||||
BCM2835_MBOX_CLOCK_ID_SDRAM, | BCM2835_FIRMWARE_CLOCK_ID_SDRAM, | ||||
MHZ2HZ(sc->sdram_max_freq)); | MHZ2HZ(sc->sdram_max_freq)); | ||||
DELAY(TRANSITION_LATENCY); | DELAY(TRANSITION_LATENCY); | ||||
} else { | } else { | ||||
if (sc->core_min_freq < DEFAULT_CORE_FREQUENCY && | if (sc->core_min_freq < DEFAULT_CORE_FREQUENCY && | ||||
core_freq > DEFAULT_CORE_FREQUENCY) { | core_freq > DEFAULT_CORE_FREQUENCY) { | ||||
/* first, down to 250, then down to min */ | /* first, down to 250, then down to min */ | ||||
DELAY(TRANSITION_LATENCY); | DELAY(TRANSITION_LATENCY); | ||||
bcm2835_cpufreq_set_clock_rate(sc, | bcm2835_cpufreq_set_clock_rate(sc, | ||||
BCM2835_MBOX_CLOCK_ID_CORE, | BCM2835_FIRMWARE_CLOCK_ID_CORE, | ||||
MHZ2HZ(DEFAULT_CORE_FREQUENCY)); | MHZ2HZ(DEFAULT_CORE_FREQUENCY)); | ||||
DELAY(TRANSITION_LATENCY); | DELAY(TRANSITION_LATENCY); | ||||
/* reset core voltage */ | /* reset core voltage */ | ||||
bcm2835_cpufreq_set_voltage(sc, | bcm2835_cpufreq_set_voltage(sc, | ||||
BCM2835_MBOX_VOLTAGE_ID_CORE, 0); | BCM2835_FIRMWARE_VOLTAGE_ID_CORE, 0); | ||||
DELAY(TRANSITION_LATENCY); | DELAY(TRANSITION_LATENCY); | ||||
} | } | ||||
bcm2835_cpufreq_set_clock_rate(sc, | bcm2835_cpufreq_set_clock_rate(sc, | ||||
BCM2835_MBOX_CLOCK_ID_CORE, | BCM2835_FIRMWARE_CLOCK_ID_CORE, | ||||
MHZ2HZ(sc->core_min_freq)); | MHZ2HZ(sc->core_min_freq)); | ||||
DELAY(TRANSITION_LATENCY); | DELAY(TRANSITION_LATENCY); | ||||
bcm2835_cpufreq_set_clock_rate(sc, | bcm2835_cpufreq_set_clock_rate(sc, | ||||
BCM2835_MBOX_CLOCK_ID_SDRAM, | BCM2835_FIRMWARE_CLOCK_ID_SDRAM, | ||||
MHZ2HZ(sc->sdram_min_freq)); | MHZ2HZ(sc->sdram_min_freq)); | ||||
DELAY(TRANSITION_LATENCY); | DELAY(TRANSITION_LATENCY); | ||||
} | } | ||||
} | } | ||||
VC_UNLOCK(sc); | VC_UNLOCK(sc); | ||||
if (resp_freq < 0 || arm_freq < 0 || resp_freq != arm_freq) { | if (resp_freq < 0 || arm_freq < 0 || resp_freq != arm_freq) { | ||||
Show All 16 Lines | bcm2835_cpufreq_get(device_t dev, struct cf_setting *cf) | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf)); | memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf)); | ||||
cf->dev = NULL; | cf->dev = NULL; | ||||
/* get cuurent value */ | /* get cuurent value */ | ||||
VC_LOCK(sc); | VC_LOCK(sc); | ||||
arm_freq = bcm2835_cpufreq_get_clock_rate(sc, | arm_freq = bcm2835_cpufreq_get_clock_rate(sc, | ||||
BCM2835_MBOX_CLOCK_ID_ARM); | BCM2835_FIRMWARE_CLOCK_ID_ARM); | ||||
VC_UNLOCK(sc); | VC_UNLOCK(sc); | ||||
if (arm_freq < 0) { | if (arm_freq < 0) { | ||||
device_printf(dev, "can't get clock\n"); | device_printf(dev, "can't get clock\n"); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
/* CPU clock in MHz or 100ths of a percent. */ | /* CPU clock in MHz or 100ths of a percent. */ | ||||
cf->freq = HZ2MHZ(arm_freq); | cf->freq = HZ2MHZ(arm_freq); | ||||
Show All 23 Lines | bcm2835_cpufreq_make_freq_list(device_t dev, struct cf_setting *sets, | ||||
/* adjust head freq to STEP */ | /* adjust head freq to STEP */ | ||||
rem = freq % MHZSTEP; | rem = freq % MHZSTEP; | ||||
freq -= rem; | freq -= rem; | ||||
if (freq < min_freq) | if (freq < min_freq) | ||||
freq = min_freq; | freq = min_freq; | ||||
/* if non-turbo, add extra low freq */ | /* if non-turbo, add extra low freq */ | ||||
if (sc->turbo_mode != BCM2835_MBOX_TURBO_ON) | if (sc->turbo_mode != BCM2835_FIRMWARE_TURBO_ON) | ||||
if (min_freq > cpufreq_lowest_freq) | if (min_freq > cpufreq_lowest_freq) | ||||
min_freq = cpufreq_lowest_freq; | min_freq = cpufreq_lowest_freq; | ||||
#ifdef SOC_BCM2835 | #ifdef SOC_BCM2835 | ||||
/* from freq to min_freq */ | /* from freq to min_freq */ | ||||
for (idx = 0; idx < *count && freq >= min_freq; idx++) { | for (idx = 0; idx < *count && freq >= min_freq; idx++) { | ||||
if (freq > sc->arm_min_freq) | if (freq > sc->arm_min_freq) | ||||
volts = sc->max_voltage_core; | volts = sc->max_voltage_core; | ||||
▲ Show 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | |||||
static driver_t bcm2835_cpufreq_driver = { | static driver_t bcm2835_cpufreq_driver = { | ||||
"bcm2835_cpufreq", | "bcm2835_cpufreq", | ||||
bcm2835_cpufreq_methods, | bcm2835_cpufreq_methods, | ||||
sizeof(struct bcm2835_cpufreq_softc), | sizeof(struct bcm2835_cpufreq_softc), | ||||
}; | }; | ||||
DRIVER_MODULE(bcm2835_cpufreq, cpu, bcm2835_cpufreq_driver, | DRIVER_MODULE(bcm2835_cpufreq, cpu, bcm2835_cpufreq_driver, | ||||
bcm2835_cpufreq_devclass, 0, 0); | bcm2835_cpufreq_devclass, 0, 0); | ||||
MODULE_DEPEND(bcm2835_cpufreq, bcm2835_firmware, 1, 1, 1); |