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