Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/evbarm/rpi Add support for rpi cpu frequency scalin...
details: https://anonhg.NetBSD.org/src/rev/edae50e53b80
branches: trunk
changeset: 783760:edae50e53b80
user: jmcneill <jmcneill%NetBSD.org@localhost>
date: Mon Jan 07 22:32:24 2013 +0000
description:
Add support for rpi cpu frequency scaling through machdep.cpu.frequency.*
sysctls. The minimum and maximum supported frequencies are based on the
"arm_freq_min" and "arm_freq" values in config.txt.
diffstat:
sys/arch/evbarm/rpi/rpi_vcmbox.c | 249 +++++++++++++++++++++++++++++++++++---
sys/arch/evbarm/rpi/vcprop.h | 4 +-
2 files changed, 227 insertions(+), 26 deletions(-)
diffs (truncated from 332 to 300 lines):
diff -r 9df225ae012f -r edae50e53b80 sys/arch/evbarm/rpi/rpi_vcmbox.c
--- a/sys/arch/evbarm/rpi/rpi_vcmbox.c Mon Jan 07 20:42:24 2013 +0000
+++ b/sys/arch/evbarm/rpi/rpi_vcmbox.c Mon Jan 07 22:32:24 2013 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: rpi_vcmbox.c,v 1.1 2013/01/07 20:19:33 jmcneill Exp $ */
+/* $NetBSD: rpi_vcmbox.c,v 1.2 2013/01/07 22:32:24 jmcneill Exp $ */
/*-
* Copyright (c) 2013 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rpi_vcmbox.c,v 1.1 2013/01/07 20:19:33 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rpi_vcmbox.c,v 1.2 2013/01/07 22:32:24 jmcneill Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -40,6 +40,7 @@
#include <sys/conf.h>
#include <sys/bus.h>
#include <sys/kmem.h>
+#include <sys/sysctl.h>
#include <dev/sysmon/sysmonvar.h>
@@ -54,6 +55,15 @@
struct vcprop_tag end;
} __packed;
+struct vcmbox_clockrate_request {
+ struct vcprop_buffer_hdr vb_hdr;
+ struct vcprop_tag_clockrate vbt_clockrate;
+ struct vcprop_tag end;
+} __packed;
+
+#define RATE2MHZ(rate) ((rate) / 1000000)
+#define MHZ2RATE(mhz) ((mhz) * 1000000)
+
#define VCMBOX_INIT_REQUEST(req) \
do { \
memset(&(req), 0, sizeof((req))); \
@@ -76,6 +86,15 @@
#define VCMBOX_SENSOR_TEMP 0
#define VCMBOX_NSENSORS 1
envsys_data_t sc_sensor[VCMBOX_NSENSORS];
+
+ /* cpu frequency scaling */
+ struct sysctllog *sc_log;
+ uint32_t sc_cpu_minrate;
+ uint32_t sc_cpu_maxrate;
+ int sc_node_target;
+ int sc_node_current;
+ int sc_node_min;
+ int sc_node_max;
};
static const char *vcmbox_sensor_name[VCMBOX_NSENSORS] = {
@@ -89,9 +108,17 @@
static int vcmbox_match(device_t, cfdata_t, void *);
static void vcmbox_attach(device_t, device_t, void *);
-static void vcmbox_create_sensors(struct vcmbox_softc *);
static int vcmbox_read_temp(struct vcmbox_softc *, uint32_t, int,
uint32_t *);
+static int vcmbox_read_clockrate(struct vcmbox_softc *, uint32_t, int,
+ uint32_t *);
+static int vcmbox_write_clockrate(struct vcmbox_softc *, uint32_t, int,
+ uint32_t);
+
+static int vcmbox_cpufreq_init(struct vcmbox_softc *);
+static int vcmbox_cpufreq_sysctl_helper(SYSCTLFN_PROTO);
+
+static void vcmbox_create_sensors(struct vcmbox_softc *);
static void vcmbox_sensor_get_limits(struct sysmon_envsys *,
envsys_data_t *,
sysmon_envsys_lim_t *, uint32_t *);
@@ -117,6 +144,8 @@
aprint_naive("\n");
aprint_normal("\n");
+ vcmbox_cpufreq_init(sc);
+
sc->sc_sme = sysmon_envsys_create();
sc->sc_sme->sme_cookie = sc;
sc->sc_sme->sme_name = device_xname(sc->sc_dev);
@@ -126,6 +155,198 @@
sysmon_envsys_register(sc->sc_sme);
}
+static int
+vcmbox_read_temp(struct vcmbox_softc *sc, uint32_t tag, int id, uint32_t *val)
+{
+ struct vcmbox_temp_request vb;
+ uint32_t res;
+ int error;
+
+ VCMBOX_INIT_REQUEST(vb);
+ VCMBOX_INIT_TAG(vb.vbt_temp, tag);
+ vb.vbt_temp.id = id;
+ error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb, sizeof(vb), &res);
+ if (error)
+ return error;
+ if (!vcprop_buffer_success_p(&vb.vb_hdr) ||
+ !vcprop_tag_success_p(&vb.vbt_temp.tag)) {
+ return EIO;
+ }
+ *val = vb.vbt_temp.value;
+
+ return 0;
+}
+
+static int
+vcmbox_read_clockrate(struct vcmbox_softc *sc, uint32_t tag, int id,
+ uint32_t *val)
+{
+ struct vcmbox_clockrate_request vb;
+ uint32_t res;
+ int error;
+
+ VCMBOX_INIT_REQUEST(vb);
+ VCMBOX_INIT_TAG(vb.vbt_clockrate, tag);
+ vb.vbt_clockrate.id = id;
+ error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb, sizeof(vb), &res);
+ if (error)
+ return error;
+ if (!vcprop_buffer_success_p(&vb.vb_hdr) ||
+ !vcprop_tag_success_p(&vb.vbt_clockrate.tag)) {
+ return EIO;
+ }
+ *val = vb.vbt_clockrate.rate;
+
+ return 0;
+}
+
+static int
+vcmbox_write_clockrate(struct vcmbox_softc *sc, uint32_t tag, int id,
+ uint32_t val)
+{
+ struct vcmbox_clockrate_request vb;
+ uint32_t res;
+ int error;
+
+ VCMBOX_INIT_REQUEST(vb);
+ VCMBOX_INIT_TAG(vb.vbt_clockrate, tag);
+ vb.vbt_clockrate.id = id;
+ vb.vbt_clockrate.rate = val;
+ error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb, sizeof(vb), &res);
+ if (error)
+ return error;
+ if (!vcprop_buffer_success_p(&vb.vb_hdr) ||
+ !vcprop_tag_success_p(&vb.vbt_clockrate.tag)) {
+ return EIO;
+ }
+
+ return 0;
+}
+
+
+static int
+vcmbox_cpufreq_init(struct vcmbox_softc *sc)
+{
+ const struct sysctlnode *node, *cpunode, *freqnode;
+ int error;
+
+ error = vcmbox_read_clockrate(sc, VCPROPTAG_GET_MIN_CLOCKRATE,
+ VCPROP_CLK_ARM, &sc->sc_cpu_minrate);
+ if (error) {
+ aprint_error_dev(sc->sc_dev, "couldn't read min clkrate (%d)\n",
+ error);
+ return error;
+ }
+ error = vcmbox_read_clockrate(sc, VCPROPTAG_GET_MAX_CLOCKRATE,
+ VCPROP_CLK_ARM, &sc->sc_cpu_maxrate);
+ if (error) {
+ aprint_error_dev(sc->sc_dev, "couldn't read max clkrate (%d)\n",
+ error);
+ return error;
+ }
+
+ error = sysctl_createv(&sc->sc_log, 0, NULL, &node,
+ CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep", NULL,
+ NULL, 0, NULL, 0, CTL_MACHDEP, CTL_EOL);
+ if (error)
+ goto sysctl_failed;
+ error = sysctl_createv(&sc->sc_log, 0, &node, &cpunode,
+ 0, CTLTYPE_NODE, "cpu", NULL,
+ NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
+ if (error)
+ goto sysctl_failed;
+ error = sysctl_createv(&sc->sc_log, 0, &cpunode, &freqnode,
+ 0, CTLTYPE_NODE, "frequency", NULL,
+ NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
+ if (error)
+ goto sysctl_failed;
+
+ error = sysctl_createv(&sc->sc_log, 0, &freqnode, &node,
+ CTLFLAG_READWRITE, CTLTYPE_INT, "target", NULL,
+ vcmbox_cpufreq_sysctl_helper, 0, (void *)sc, 0,
+ CTL_CREATE, CTL_EOL);
+ if (error)
+ goto sysctl_failed;
+ sc->sc_node_target = node->sysctl_num;
+
+ error = sysctl_createv(&sc->sc_log, 0, &freqnode, &node,
+ 0, CTLTYPE_INT, "current", NULL,
+ vcmbox_cpufreq_sysctl_helper, 0, (void *)sc, 0,
+ CTL_CREATE, CTL_EOL);
+ if (error)
+ goto sysctl_failed;
+ sc->sc_node_current = node->sysctl_num;
+
+ error = sysctl_createv(&sc->sc_log, 0, &freqnode, &node,
+ 0, CTLTYPE_INT, "min", NULL,
+ vcmbox_cpufreq_sysctl_helper, 0, (void *)sc, 0,
+ CTL_CREATE, CTL_EOL);
+ if (error)
+ goto sysctl_failed;
+ sc->sc_node_min = node->sysctl_num;
+
+ error = sysctl_createv(&sc->sc_log, 0, &freqnode, &node,
+ 0, CTLTYPE_INT, "max", NULL,
+ vcmbox_cpufreq_sysctl_helper, 0, (void *)sc, 0,
+ CTL_CREATE, CTL_EOL);
+ if (error)
+ goto sysctl_failed;
+ sc->sc_node_max = node->sysctl_num;
+
+ return 0;
+
+sysctl_failed:
+ aprint_error_dev(sc->sc_dev, "couldn't create sysctl nodes (%d)\n",
+ error);
+ sysctl_teardown(&sc->sc_log);
+ return error;
+}
+
+static int
+vcmbox_cpufreq_sysctl_helper(SYSCTLFN_ARGS)
+{
+ struct sysctlnode node;
+ struct vcmbox_softc *sc;
+ int fq, oldfq = 0, error;
+ uint32_t rate;
+
+ node = *rnode;
+ sc = node.sysctl_data;
+
+ node.sysctl_data = &fq;
+
+ if (rnode->sysctl_num == sc->sc_node_target ||
+ rnode->sysctl_num == sc->sc_node_current) {
+ error = vcmbox_read_clockrate(sc, VCPROPTAG_GET_CLOCKRATE,
+ VCPROP_CLK_ARM, &rate);
+ if (error)
+ return error;
+ fq = RATE2MHZ(rate);
+ if (rnode->sysctl_num == sc->sc_node_target)
+ oldfq = fq;
+ } else if (rnode->sysctl_num == sc->sc_node_min) {
+ fq = RATE2MHZ(sc->sc_cpu_minrate);
+ } else if (rnode->sysctl_num == sc->sc_node_max) {
+ fq = RATE2MHZ(sc->sc_cpu_maxrate);
+ } else
+ return EOPNOTSUPP;
+
+ error = sysctl_lookup(SYSCTLFN_CALL(&node));
+ if (error || newp == NULL)
+ return error;
+
+ if (fq == oldfq || rnode->sysctl_num != sc->sc_node_target)
+ return 0;
+
+ if (fq < RATE2MHZ(sc->sc_cpu_minrate))
+ fq = RATE2MHZ(sc->sc_cpu_minrate);
+ if (fq > RATE2MHZ(sc->sc_cpu_maxrate))
+ fq = RATE2MHZ(sc->sc_cpu_maxrate);
+
+ return vcmbox_write_clockrate(sc, VCPROPTAG_SET_CLOCKRATE,
+ VCPROP_CLK_ARM, MHZ2RATE(fq));
+}
+
static void
vcmbox_create_sensors(struct vcmbox_softc *sc)
{
@@ -148,28 +369,6 @@
&sc->sc_sensor[VCMBOX_SENSOR_TEMP]);
}
-static int
-vcmbox_read_temp(struct vcmbox_softc *sc, uint32_t tag, int id, uint32_t *val)
-{
- struct vcmbox_temp_request vb;
- uint32_t res;
- int error;
-
- VCMBOX_INIT_REQUEST(vb);
- VCMBOX_INIT_TAG(vb.vbt_temp, tag);
- vb.vbt_temp.id = id;
- error = bcmmbox_request(BCMMBOX_CHANARM2VC, &vb, sizeof(vb), &res);
Home |
Main Index |
Thread Index |
Old Index