Path: blob/main/sys/arm/broadcom/bcm2835/bcm2835_cpufreq.c
39566 views
/*-1* Copyright (C) 2013-2015 Daisuke Aoyama <[email protected]>2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*25*/2627#include <sys/param.h>28#include <sys/systm.h>29#include <sys/bus.h>30#include <sys/cpu.h>31#include <sys/kernel.h>32#include <sys/lock.h>33#include <sys/malloc.h>34#include <sys/module.h>35#include <sys/mutex.h>36#include <sys/sema.h>37#include <sys/sysctl.h>3839#include <machine/bus.h>40#include <machine/cpu.h>41#include <machine/intr.h>4243#include <dev/ofw/ofw_bus.h>44#include <dev/ofw/ofw_bus_subr.h>4546#include <arm/broadcom/bcm2835/bcm2835_firmware.h>47#include <arm/broadcom/bcm2835/bcm2835_vcbus.h>4849#include "cpufreq_if.h"5051#ifdef DEBUG52#define DPRINTF(fmt, ...) do { \53printf("%s:%u: ", __func__, __LINE__); \54printf(fmt, ##__VA_ARGS__); \55} while (0)56#else57#define DPRINTF(fmt, ...)58#endif5960#define HZ2MHZ(freq) ((freq) / (1000 * 1000))61#define MHZ2HZ(freq) ((freq) * (1000 * 1000))6263#define OFFSET2MVOLT(val) (((val) / 1000))64#define MVOLT2OFFSET(val) (((val) * 1000))65#define DEFAULT_ARM_FREQUENCY 60066#define DEFAULT_LOWEST_FREQ 60067#define DEFAULT_CORE_FREQUENCY 25068#define DEFAULT_SDRAM_FREQUENCY 40069#define TRANSITION_LATENCY 100070#define MIN_OVER_VOLTAGE -1671#define MAX_OVER_VOLTAGE 672#define MSG_ERROR -99999999973#define MHZSTEP 10074#define HZSTEP (MHZ2HZ(MHZSTEP))75#define TZ_ZEROC 27317677#define VC_LOCK(sc) do { \78sema_wait(&vc_sema); \79} while (0)80#define VC_UNLOCK(sc) do { \81sema_post(&vc_sema); \82} while (0)8384/* ARM->VC mailbox property semaphore */85static struct sema vc_sema;8687static struct sysctl_ctx_list bcm2835_sysctl_ctx;8889struct bcm2835_cpufreq_softc {90device_t dev;91device_t firmware;92int arm_max_freq;93int arm_min_freq;94int core_max_freq;95int core_min_freq;96int sdram_max_freq;97int sdram_min_freq;98int max_voltage_core;99int min_voltage_core;100101/* the values written in mbox */102int voltage_core;103int voltage_sdram;104int voltage_sdram_c;105int voltage_sdram_i;106int voltage_sdram_p;107int turbo_mode;108109/* initial hook for waiting mbox intr */110struct intr_config_hook init_hook;111};112113static struct ofw_compat_data compat_data[] = {114{ "broadcom,bcm2835-vc", 1 },115{ "broadcom,bcm2708-vc", 1 },116{ "brcm,bcm2709", 1 },117{ "brcm,bcm2835", 1 },118{ "brcm,bcm2836", 1 },119{ "brcm,bcm2837", 1 },120{ "brcm,bcm2711", 1 },121{ NULL, 0 }122};123124static int cpufreq_verbose = 0;125TUNABLE_INT("hw.bcm2835.cpufreq.verbose", &cpufreq_verbose);126static int cpufreq_lowest_freq = DEFAULT_LOWEST_FREQ;127TUNABLE_INT("hw.bcm2835.cpufreq.lowest_freq", &cpufreq_lowest_freq);128129#ifdef PROP_DEBUG130static void131bcm2835_dump(const void *data, int len)132{133const uint8_t *p = (const uint8_t*)data;134int i;135136printf("dump @ %p:\n", data);137for (i = 0; i < len; i++) {138printf("%2.2x ", p[i]);139if ((i % 4) == 3)140printf(" ");141if ((i % 16) == 15)142printf("\n");143}144printf("\n");145}146#endif147148static int149bcm2835_cpufreq_get_clock_rate(struct bcm2835_cpufreq_softc *sc,150uint32_t clock_id)151{152union msg_get_clock_rate_body msg;153int rate;154int err;155156/*157* Get clock rate158* Tag: 0x00030002159* Request:160* Length: 4161* Value:162* u32: clock id163* Response:164* Length: 8165* Value:166* u32: clock id167* u32: rate (in Hz)168*/169170/* setup single tag buffer */171memset(&msg, 0, sizeof(msg));172msg.req.clock_id = clock_id;173174/* call mailbox property */175err = bcm2835_firmware_property(sc->firmware,176BCM2835_FIRMWARE_TAG_GET_CLOCK_RATE, &msg, sizeof(msg));177if (err) {178device_printf(sc->dev, "can't get clock rate (id=%u)\n",179clock_id);180return (MSG_ERROR);181}182183/* result (Hz) */184rate = (int)msg.resp.rate_hz;185DPRINTF("clock = %d(Hz)\n", rate);186return (rate);187}188189static int190bcm2835_cpufreq_get_max_clock_rate(struct bcm2835_cpufreq_softc *sc,191uint32_t clock_id)192{193union msg_get_clock_rate_body msg;194int rate;195int err;196197/*198* Get max clock rate199* Tag: 0x00030004200* Request:201* Length: 4202* Value:203* u32: clock id204* Response:205* Length: 8206* Value:207* u32: clock id208* u32: rate (in Hz)209*/210211/* setup single tag buffer */212memset(&msg, 0, sizeof(msg));213msg.req.clock_id = clock_id;214215/* call mailbox property */216err = bcm2835_firmware_property(sc->firmware,217BCM2835_FIRMWARE_TAG_GET_MAX_CLOCK_RATE, &msg, sizeof(msg));218if (err) {219device_printf(sc->dev, "can't get max clock rate (id=%u)\n",220clock_id);221return (MSG_ERROR);222}223224/* result (Hz) */225rate = (int)msg.resp.rate_hz;226DPRINTF("clock = %d(Hz)\n", rate);227return (rate);228}229230static int231bcm2835_cpufreq_get_min_clock_rate(struct bcm2835_cpufreq_softc *sc,232uint32_t clock_id)233{234union msg_get_clock_rate_body msg;235int rate;236int err;237238/*239* Get min clock rate240* Tag: 0x00030007241* Request:242* Length: 4243* Value:244* u32: clock id245* Response:246* Length: 8247* Value:248* u32: clock id249* u32: rate (in Hz)250*/251252/* setup single tag buffer */253memset(&msg, 0, sizeof(msg));254msg.req.clock_id = clock_id;255256/* call mailbox property */257err = bcm2835_firmware_property(sc->firmware,258BCM2835_FIRMWARE_TAG_GET_MIN_CLOCK_RATE, &msg, sizeof(msg));259if (err) {260device_printf(sc->dev, "can't get min clock rate (id=%u)\n",261clock_id);262return (MSG_ERROR);263}264265/* result (Hz) */266rate = (int)msg.resp.rate_hz;267DPRINTF("clock = %d(Hz)\n", rate);268return (rate);269}270271static int272bcm2835_cpufreq_set_clock_rate(struct bcm2835_cpufreq_softc *sc,273uint32_t clock_id, uint32_t rate_hz)274{275union msg_set_clock_rate_body msg;276int rate;277int err;278279/*280* Set clock rate281* Tag: 0x00038002282* Request:283* Length: 8284* Value:285* u32: clock id286* u32: rate (in Hz)287* Response:288* Length: 8289* Value:290* u32: clock id291* u32: rate (in Hz)292*/293294/* setup single tag buffer */295memset(&msg, 0, sizeof(msg));296msg.req.clock_id = clock_id;297msg.req.rate_hz = rate_hz;298299/* call mailbox property */300err = bcm2835_firmware_property(sc->firmware,301BCM2835_FIRMWARE_TAG_SET_CLOCK_RATE, &msg, sizeof(msg));302if (err) {303device_printf(sc->dev, "can't set clock rate (id=%u)\n",304clock_id);305return (MSG_ERROR);306}307308/* workaround for core clock */309if (clock_id == BCM2835_FIRMWARE_CLOCK_ID_CORE) {310/* for safety (may change voltage without changing clock) */311DELAY(TRANSITION_LATENCY);312313/*314* XXX: the core clock is unable to change at once,315* to change certainly, write it twice now.316*/317318/* setup single tag buffer */319memset(&msg, 0, sizeof(msg));320msg.req.clock_id = clock_id;321msg.req.rate_hz = rate_hz;322323/* call mailbox property */324err = bcm2835_firmware_property(sc->firmware,325BCM2835_FIRMWARE_TAG_SET_CLOCK_RATE, &msg, sizeof(msg));326if (err) {327device_printf(sc->dev,328"can't set clock rate (id=%u)\n", clock_id);329return (MSG_ERROR);330}331}332333/* result (Hz) */334rate = (int)msg.resp.rate_hz;335DPRINTF("clock = %d(Hz)\n", rate);336return (rate);337}338339static int340bcm2835_cpufreq_get_turbo(struct bcm2835_cpufreq_softc *sc)341{342union msg_get_turbo_body msg;343int level;344int err;345346/*347* Get turbo348* Tag: 0x00030009349* Request:350* Length: 4351* Value:352* u32: id353* Response:354* Length: 8355* Value:356* u32: id357* u32: level358*/359360/* setup single tag buffer */361memset(&msg, 0, sizeof(msg));362msg.req.id = 0;363364/* call mailbox property */365err = bcm2835_firmware_property(sc->firmware,366BCM2835_FIRMWARE_TAG_GET_TURBO, &msg, sizeof(msg));367if (err) {368device_printf(sc->dev, "can't get turbo\n");369return (MSG_ERROR);370}371372/* result 0=non-turbo, 1=turbo */373level = (int)msg.resp.level;374DPRINTF("level = %d\n", level);375return (level);376}377378static int379bcm2835_cpufreq_set_turbo(struct bcm2835_cpufreq_softc *sc, uint32_t level)380{381union msg_set_turbo_body msg;382int value;383int err;384385/*386* Set turbo387* Tag: 0x00038009388* Request:389* Length: 8390* Value:391* u32: id392* u32: level393* Response:394* Length: 8395* Value:396* u32: id397* u32: level398*/399400/* replace unknown value to OFF */401if (level != BCM2835_FIRMWARE_TURBO_ON &&402level != BCM2835_FIRMWARE_TURBO_OFF)403level = BCM2835_FIRMWARE_TURBO_OFF;404405/* setup single tag buffer */406memset(&msg, 0, sizeof(msg));407msg.req.id = 0;408msg.req.level = level;409410/* call mailbox property */411err = bcm2835_firmware_property(sc->firmware,412BCM2835_FIRMWARE_TAG_SET_TURBO, &msg, sizeof(msg));413if (err) {414device_printf(sc->dev, "can't set turbo\n");415return (MSG_ERROR);416}417418/* result 0=non-turbo, 1=turbo */419value = (int)msg.resp.level;420DPRINTF("level = %d\n", value);421return (value);422}423424static int425bcm2835_cpufreq_get_voltage(struct bcm2835_cpufreq_softc *sc,426uint32_t voltage_id)427{428union msg_get_voltage_body msg;429int value;430int err;431432/*433* Get voltage434* Tag: 0x00030003435* Request:436* Length: 4437* Value:438* u32: voltage id439* Response:440* Length: 8441* Value:442* u32: voltage id443* u32: value (offset from 1.2V in units of 0.025V)444*/445446/* setup single tag buffer */447memset(&msg, 0, sizeof(msg));448msg.req.voltage_id = voltage_id;449450/* call mailbox property */451err = bcm2835_firmware_property(sc->firmware,452BCM2835_FIRMWARE_TAG_GET_VOLTAGE, &msg, sizeof(msg));453if (err) {454device_printf(sc->dev, "can't get voltage\n");455return (MSG_ERROR);456}457458/* result (offset from 1.2V) */459value = (int)msg.resp.value;460DPRINTF("value = %d\n", value);461return (value);462}463464static int465bcm2835_cpufreq_get_max_voltage(struct bcm2835_cpufreq_softc *sc,466uint32_t voltage_id)467{468union msg_get_voltage_body msg;469int value;470int err;471472/*473* Get voltage474* Tag: 0x00030005475* Request:476* Length: 4477* Value:478* u32: voltage id479* Response:480* Length: 8481* Value:482* u32: voltage id483* u32: value (offset from 1.2V in units of 0.025V)484*/485486/* setup single tag buffer */487memset(&msg, 0, sizeof(msg));488msg.req.voltage_id = voltage_id;489490/* call mailbox property */491err = bcm2835_firmware_property(sc->firmware,492BCM2835_FIRMWARE_TAG_GET_MAX_VOLTAGE, &msg, sizeof(msg));493if (err) {494device_printf(sc->dev, "can't get max voltage\n");495return (MSG_ERROR);496}497498/* result (offset from 1.2V) */499value = (int)msg.resp.value;500DPRINTF("value = %d\n", value);501return (value);502}503static int504bcm2835_cpufreq_get_min_voltage(struct bcm2835_cpufreq_softc *sc,505uint32_t voltage_id)506{507union msg_get_voltage_body msg;508int value;509int err;510511/*512* Get voltage513* Tag: 0x00030008514* Request:515* Length: 4516* Value:517* u32: voltage id518* Response:519* Length: 8520* Value:521* u32: voltage id522* u32: value (offset from 1.2V in units of 0.025V)523*/524525/* setup single tag buffer */526memset(&msg, 0, sizeof(msg));527msg.req.voltage_id = voltage_id;528529/* call mailbox property */530err = bcm2835_firmware_property(sc->firmware,531BCM2835_FIRMWARE_TAG_GET_MIN_VOLTAGE, &msg, sizeof(msg));532if (err) {533device_printf(sc->dev, "can't get min voltage\n");534return (MSG_ERROR);535}536537/* result (offset from 1.2V) */538value = (int)msg.resp.value;539DPRINTF("value = %d\n", value);540return (value);541}542543static int544bcm2835_cpufreq_set_voltage(struct bcm2835_cpufreq_softc *sc,545uint32_t voltage_id, int32_t value)546{547union msg_set_voltage_body msg;548int err;549550/*551* Set voltage552* Tag: 0x00038003553* Request:554* Length: 4555* Value:556* u32: voltage id557* u32: value (offset from 1.2V in units of 0.025V)558* Response:559* Length: 8560* Value:561* u32: voltage id562* u32: value (offset from 1.2V in units of 0.025V)563*/564565/*566* over_voltage:567* 0 (1.2 V). Values above 6 are only allowed when force_turbo or568* current_limit_override are specified (which set the warranty bit).569*/570if (value > MAX_OVER_VOLTAGE || value < MIN_OVER_VOLTAGE) {571/* currently not supported */572device_printf(sc->dev, "not supported voltage: %d\n", value);573return (MSG_ERROR);574}575576/* setup single tag buffer */577memset(&msg, 0, sizeof(msg));578msg.req.voltage_id = voltage_id;579msg.req.value = (uint32_t)value;580581/* call mailbox property */582err = bcm2835_firmware_property(sc->firmware,583BCM2835_FIRMWARE_TAG_SET_VOLTAGE, &msg, sizeof(msg));584if (err) {585device_printf(sc->dev, "can't set voltage\n");586return (MSG_ERROR);587}588589/* result (offset from 1.2V) */590value = (int)msg.resp.value;591DPRINTF("value = %d\n", value);592return (value);593}594595static int596bcm2835_cpufreq_get_temperature(struct bcm2835_cpufreq_softc *sc)597{598union msg_get_temperature_body msg;599int value;600int err;601602/*603* Get temperature604* Tag: 0x00030006605* Request:606* Length: 4607* Value:608* u32: temperature id609* Response:610* Length: 8611* Value:612* u32: temperature id613* u32: value614*/615616/* setup single tag buffer */617memset(&msg, 0, sizeof(msg));618msg.req.temperature_id = 0;619620/* call mailbox property */621err = bcm2835_firmware_property(sc->firmware,622BCM2835_FIRMWARE_TAG_GET_TEMPERATURE, &msg, sizeof(msg));623if (err) {624device_printf(sc->dev, "can't get temperature\n");625return (MSG_ERROR);626}627628/* result (temperature of degree C) */629value = (int)msg.resp.value;630DPRINTF("value = %d\n", value);631return (value);632}633634static int635sysctl_bcm2835_cpufreq_arm_freq(SYSCTL_HANDLER_ARGS)636{637struct bcm2835_cpufreq_softc *sc = arg1;638int val;639int err;640641/* get realtime value */642VC_LOCK(sc);643val = bcm2835_cpufreq_get_clock_rate(sc, BCM2835_FIRMWARE_CLOCK_ID_ARM);644VC_UNLOCK(sc);645if (val == MSG_ERROR)646return (EIO);647648err = sysctl_handle_int(oidp, &val, 0, req);649if (err || !req->newptr) /* error || read request */650return (err);651652/* write request */653VC_LOCK(sc);654err = bcm2835_cpufreq_set_clock_rate(sc, BCM2835_FIRMWARE_CLOCK_ID_ARM,655val);656VC_UNLOCK(sc);657if (err == MSG_ERROR) {658device_printf(sc->dev, "set clock arm_freq error\n");659return (EIO);660}661DELAY(TRANSITION_LATENCY);662663return (0);664}665666static int667sysctl_bcm2835_cpufreq_core_freq(SYSCTL_HANDLER_ARGS)668{669struct bcm2835_cpufreq_softc *sc = arg1;670int val;671int err;672673/* get realtime value */674VC_LOCK(sc);675val = bcm2835_cpufreq_get_clock_rate(sc,676BCM2835_FIRMWARE_CLOCK_ID_CORE);677VC_UNLOCK(sc);678if (val == MSG_ERROR)679return (EIO);680681err = sysctl_handle_int(oidp, &val, 0, req);682if (err || !req->newptr) /* error || read request */683return (err);684685/* write request */686VC_LOCK(sc);687err = bcm2835_cpufreq_set_clock_rate(sc, BCM2835_FIRMWARE_CLOCK_ID_CORE,688val);689if (err == MSG_ERROR) {690VC_UNLOCK(sc);691device_printf(sc->dev, "set clock core_freq error\n");692return (EIO);693}694VC_UNLOCK(sc);695DELAY(TRANSITION_LATENCY);696697return (0);698}699700static int701sysctl_bcm2835_cpufreq_sdram_freq(SYSCTL_HANDLER_ARGS)702{703struct bcm2835_cpufreq_softc *sc = arg1;704int val;705int err;706707/* get realtime value */708VC_LOCK(sc);709val = bcm2835_cpufreq_get_clock_rate(sc,710BCM2835_FIRMWARE_CLOCK_ID_SDRAM);711VC_UNLOCK(sc);712if (val == MSG_ERROR)713return (EIO);714715err = sysctl_handle_int(oidp, &val, 0, req);716if (err || !req->newptr) /* error || read request */717return (err);718719/* write request */720VC_LOCK(sc);721err = bcm2835_cpufreq_set_clock_rate(sc,722BCM2835_FIRMWARE_CLOCK_ID_SDRAM, val);723VC_UNLOCK(sc);724if (err == MSG_ERROR) {725device_printf(sc->dev, "set clock sdram_freq error\n");726return (EIO);727}728DELAY(TRANSITION_LATENCY);729730return (0);731}732733static int734sysctl_bcm2835_cpufreq_turbo(SYSCTL_HANDLER_ARGS)735{736struct bcm2835_cpufreq_softc *sc = arg1;737int val;738int err;739740/* get realtime value */741VC_LOCK(sc);742val = bcm2835_cpufreq_get_turbo(sc);743VC_UNLOCK(sc);744if (val == MSG_ERROR)745return (EIO);746747err = sysctl_handle_int(oidp, &val, 0, req);748if (err || !req->newptr) /* error || read request */749return (err);750751/* write request */752if (val > 0)753sc->turbo_mode = BCM2835_FIRMWARE_TURBO_ON;754else755sc->turbo_mode = BCM2835_FIRMWARE_TURBO_OFF;756757VC_LOCK(sc);758err = bcm2835_cpufreq_set_turbo(sc, sc->turbo_mode);759VC_UNLOCK(sc);760if (err == MSG_ERROR) {761device_printf(sc->dev, "set turbo error\n");762return (EIO);763}764DELAY(TRANSITION_LATENCY);765766return (0);767}768769static int770sysctl_bcm2835_cpufreq_voltage_core(SYSCTL_HANDLER_ARGS)771{772struct bcm2835_cpufreq_softc *sc = arg1;773int val;774int err;775776/* get realtime value */777VC_LOCK(sc);778val = bcm2835_cpufreq_get_voltage(sc, BCM2835_FIRMWARE_VOLTAGE_ID_CORE);779VC_UNLOCK(sc);780if (val == MSG_ERROR)781return (EIO);782783err = sysctl_handle_int(oidp, &val, 0, req);784if (err || !req->newptr) /* error || read request */785return (err);786787/* write request */788if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE)789return (EINVAL);790sc->voltage_core = val;791792VC_LOCK(sc);793err = bcm2835_cpufreq_set_voltage(sc, BCM2835_FIRMWARE_VOLTAGE_ID_CORE,794sc->voltage_core);795VC_UNLOCK(sc);796if (err == MSG_ERROR) {797device_printf(sc->dev, "set voltage core error\n");798return (EIO);799}800DELAY(TRANSITION_LATENCY);801802return (0);803}804805static int806sysctl_bcm2835_cpufreq_voltage_sdram_c(SYSCTL_HANDLER_ARGS)807{808struct bcm2835_cpufreq_softc *sc = arg1;809int val;810int err;811812/* get realtime value */813VC_LOCK(sc);814val = bcm2835_cpufreq_get_voltage(sc,815BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_C);816VC_UNLOCK(sc);817if (val == MSG_ERROR)818return (EIO);819820err = sysctl_handle_int(oidp, &val, 0, req);821if (err || !req->newptr) /* error || read request */822return (err);823824/* write request */825if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE)826return (EINVAL);827sc->voltage_sdram_c = val;828829VC_LOCK(sc);830err = bcm2835_cpufreq_set_voltage(sc,831BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_C,832sc->voltage_sdram_c);833VC_UNLOCK(sc);834if (err == MSG_ERROR) {835device_printf(sc->dev, "set voltage sdram_c error\n");836return (EIO);837}838DELAY(TRANSITION_LATENCY);839840return (0);841}842843static int844sysctl_bcm2835_cpufreq_voltage_sdram_i(SYSCTL_HANDLER_ARGS)845{846struct bcm2835_cpufreq_softc *sc = arg1;847int val;848int err;849850/* get realtime value */851VC_LOCK(sc);852val = bcm2835_cpufreq_get_voltage(sc,853BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_I);854VC_UNLOCK(sc);855if (val == MSG_ERROR)856return (EIO);857858err = sysctl_handle_int(oidp, &val, 0, req);859if (err || !req->newptr) /* error || read request */860return (err);861862/* write request */863if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE)864return (EINVAL);865sc->voltage_sdram_i = val;866867VC_LOCK(sc);868err = bcm2835_cpufreq_set_voltage(sc,869BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_I, sc->voltage_sdram_i);870VC_UNLOCK(sc);871if (err == MSG_ERROR) {872device_printf(sc->dev, "set voltage sdram_i error\n");873return (EIO);874}875DELAY(TRANSITION_LATENCY);876877return (0);878}879880static int881sysctl_bcm2835_cpufreq_voltage_sdram_p(SYSCTL_HANDLER_ARGS)882{883struct bcm2835_cpufreq_softc *sc = arg1;884int val;885int err;886887/* get realtime value */888VC_LOCK(sc);889val = bcm2835_cpufreq_get_voltage(sc,890BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_P);891VC_UNLOCK(sc);892if (val == MSG_ERROR)893return (EIO);894895err = sysctl_handle_int(oidp, &val, 0, req);896if (err || !req->newptr) /* error || read request */897return (err);898899/* write request */900if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE)901return (EINVAL);902sc->voltage_sdram_p = val;903904VC_LOCK(sc);905err = bcm2835_cpufreq_set_voltage(sc,906BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_P, sc->voltage_sdram_p);907VC_UNLOCK(sc);908if (err == MSG_ERROR) {909device_printf(sc->dev, "set voltage sdram_p error\n");910return (EIO);911}912DELAY(TRANSITION_LATENCY);913914return (0);915}916917static int918sysctl_bcm2835_cpufreq_voltage_sdram(SYSCTL_HANDLER_ARGS)919{920struct bcm2835_cpufreq_softc *sc = arg1;921int val;922int err;923924/* multiple write only */925if (!req->newptr)926return (EINVAL);927val = 0;928err = sysctl_handle_int(oidp, &val, 0, req);929if (err)930return (err);931932/* write request */933if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE)934return (EINVAL);935sc->voltage_sdram = val;936937VC_LOCK(sc);938err = bcm2835_cpufreq_set_voltage(sc,939BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_C, val);940if (err == MSG_ERROR) {941VC_UNLOCK(sc);942device_printf(sc->dev, "set voltage sdram_c error\n");943return (EIO);944}945err = bcm2835_cpufreq_set_voltage(sc,946BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_I, val);947if (err == MSG_ERROR) {948VC_UNLOCK(sc);949device_printf(sc->dev, "set voltage sdram_i error\n");950return (EIO);951}952err = bcm2835_cpufreq_set_voltage(sc,953BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_P, val);954if (err == MSG_ERROR) {955VC_UNLOCK(sc);956device_printf(sc->dev, "set voltage sdram_p error\n");957return (EIO);958}959VC_UNLOCK(sc);960DELAY(TRANSITION_LATENCY);961962return (0);963}964965static int966sysctl_bcm2835_cpufreq_temperature(SYSCTL_HANDLER_ARGS)967{968struct bcm2835_cpufreq_softc *sc = arg1;969int val;970int err;971972/* get realtime value */973VC_LOCK(sc);974val = bcm2835_cpufreq_get_temperature(sc);975VC_UNLOCK(sc);976if (val == MSG_ERROR)977return (EIO);978979err = sysctl_handle_int(oidp, &val, 0, req);980if (err || !req->newptr) /* error || read request */981return (err);982983/* write request */984return (EINVAL);985}986987static int988sysctl_bcm2835_devcpu_temperature(SYSCTL_HANDLER_ARGS)989{990struct bcm2835_cpufreq_softc *sc = arg1;991int val;992int err;993994/* get realtime value */995VC_LOCK(sc);996val = bcm2835_cpufreq_get_temperature(sc);997VC_UNLOCK(sc);998if (val == MSG_ERROR)999return (EIO);10001001/* 1/1000 celsius (raw) to 1/10 kelvin */1002val = val / 100 + TZ_ZEROC;10031004err = sysctl_handle_int(oidp, &val, 0, req);1005if (err || !req->newptr) /* error || read request */1006return (err);10071008/* write request */1009return (EINVAL);1010}10111012static void1013bcm2835_cpufreq_init(void *arg)1014{1015struct bcm2835_cpufreq_softc *sc = arg;1016struct sysctl_ctx_list *ctx;1017device_t cpu;1018int arm_freq, core_freq, sdram_freq;1019int arm_max_freq, arm_min_freq, core_max_freq, core_min_freq;1020int sdram_max_freq, sdram_min_freq;1021int voltage_core, voltage_sdram_c, voltage_sdram_i, voltage_sdram_p;1022int max_voltage_core, min_voltage_core;1023int max_voltage_sdram_c, min_voltage_sdram_c;1024int max_voltage_sdram_i, min_voltage_sdram_i;1025int max_voltage_sdram_p, min_voltage_sdram_p;1026int turbo, temperature;10271028VC_LOCK(sc);10291030/* current clock */1031arm_freq = bcm2835_cpufreq_get_clock_rate(sc,1032BCM2835_FIRMWARE_CLOCK_ID_ARM);1033core_freq = bcm2835_cpufreq_get_clock_rate(sc,1034BCM2835_FIRMWARE_CLOCK_ID_CORE);1035sdram_freq = bcm2835_cpufreq_get_clock_rate(sc,1036BCM2835_FIRMWARE_CLOCK_ID_SDRAM);10371038/* max/min clock */1039arm_max_freq = bcm2835_cpufreq_get_max_clock_rate(sc,1040BCM2835_FIRMWARE_CLOCK_ID_ARM);1041arm_min_freq = bcm2835_cpufreq_get_min_clock_rate(sc,1042BCM2835_FIRMWARE_CLOCK_ID_ARM);1043core_max_freq = bcm2835_cpufreq_get_max_clock_rate(sc,1044BCM2835_FIRMWARE_CLOCK_ID_CORE);1045core_min_freq = bcm2835_cpufreq_get_min_clock_rate(sc,1046BCM2835_FIRMWARE_CLOCK_ID_CORE);1047sdram_max_freq = bcm2835_cpufreq_get_max_clock_rate(sc,1048BCM2835_FIRMWARE_CLOCK_ID_SDRAM);1049sdram_min_freq = bcm2835_cpufreq_get_min_clock_rate(sc,1050BCM2835_FIRMWARE_CLOCK_ID_SDRAM);10511052/* turbo mode */1053turbo = bcm2835_cpufreq_get_turbo(sc);1054if (turbo > 0)1055sc->turbo_mode = BCM2835_FIRMWARE_TURBO_ON;1056else1057sc->turbo_mode = BCM2835_FIRMWARE_TURBO_OFF;10581059/* voltage */1060voltage_core = bcm2835_cpufreq_get_voltage(sc,1061BCM2835_FIRMWARE_VOLTAGE_ID_CORE);1062voltage_sdram_c = bcm2835_cpufreq_get_voltage(sc,1063BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_C);1064voltage_sdram_i = bcm2835_cpufreq_get_voltage(sc,1065BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_I);1066voltage_sdram_p = bcm2835_cpufreq_get_voltage(sc,1067BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_P);10681069/* current values (offset from 1.2V) */1070sc->voltage_core = voltage_core;1071sc->voltage_sdram = voltage_sdram_c;1072sc->voltage_sdram_c = voltage_sdram_c;1073sc->voltage_sdram_i = voltage_sdram_i;1074sc->voltage_sdram_p = voltage_sdram_p;10751076/* max/min voltage */1077max_voltage_core = bcm2835_cpufreq_get_max_voltage(sc,1078BCM2835_FIRMWARE_VOLTAGE_ID_CORE);1079min_voltage_core = bcm2835_cpufreq_get_min_voltage(sc,1080BCM2835_FIRMWARE_VOLTAGE_ID_CORE);1081max_voltage_sdram_c = bcm2835_cpufreq_get_max_voltage(sc,1082BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_C);1083max_voltage_sdram_i = bcm2835_cpufreq_get_max_voltage(sc,1084BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_I);1085max_voltage_sdram_p = bcm2835_cpufreq_get_max_voltage(sc,1086BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_P);1087min_voltage_sdram_c = bcm2835_cpufreq_get_min_voltage(sc,1088BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_C);1089min_voltage_sdram_i = bcm2835_cpufreq_get_min_voltage(sc,1090BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_I);1091min_voltage_sdram_p = bcm2835_cpufreq_get_min_voltage(sc,1092BCM2835_FIRMWARE_VOLTAGE_ID_SDRAM_P);10931094/* temperature */1095temperature = bcm2835_cpufreq_get_temperature(sc);10961097/* show result */1098if (cpufreq_verbose || bootverbose) {1099device_printf(sc->dev, "Boot settings:\n");1100device_printf(sc->dev,1101"current ARM %dMHz, Core %dMHz, SDRAM %dMHz, Turbo %s\n",1102HZ2MHZ(arm_freq), HZ2MHZ(core_freq), HZ2MHZ(sdram_freq),1103(sc->turbo_mode == BCM2835_FIRMWARE_TURBO_ON) ? "ON":"OFF");11041105device_printf(sc->dev,1106"max/min ARM %d/%dMHz, Core %d/%dMHz, SDRAM %d/%dMHz\n",1107HZ2MHZ(arm_max_freq), HZ2MHZ(arm_min_freq),1108HZ2MHZ(core_max_freq), HZ2MHZ(core_min_freq),1109HZ2MHZ(sdram_max_freq), HZ2MHZ(sdram_min_freq));11101111device_printf(sc->dev,1112"current Core %dmV, SDRAM_C %dmV, SDRAM_I %dmV, "1113"SDRAM_P %dmV\n",1114OFFSET2MVOLT(voltage_core), OFFSET2MVOLT(voltage_sdram_c),1115OFFSET2MVOLT(voltage_sdram_i),1116OFFSET2MVOLT(voltage_sdram_p));11171118device_printf(sc->dev,1119"max/min Core %d/%dmV, SDRAM_C %d/%dmV, SDRAM_I %d/%dmV, "1120"SDRAM_P %d/%dmV\n",1121OFFSET2MVOLT(max_voltage_core),1122OFFSET2MVOLT(min_voltage_core),1123OFFSET2MVOLT(max_voltage_sdram_c),1124OFFSET2MVOLT(min_voltage_sdram_c),1125OFFSET2MVOLT(max_voltage_sdram_i),1126OFFSET2MVOLT(min_voltage_sdram_i),1127OFFSET2MVOLT(max_voltage_sdram_p),1128OFFSET2MVOLT(min_voltage_sdram_p));11291130device_printf(sc->dev,1131"Temperature %d.%dC\n", (temperature / 1000),1132(temperature % 1000) / 100);1133} else { /* !cpufreq_verbose && !bootverbose */1134device_printf(sc->dev,1135"ARM %dMHz, Core %dMHz, SDRAM %dMHz, Turbo %s\n",1136HZ2MHZ(arm_freq), HZ2MHZ(core_freq), HZ2MHZ(sdram_freq),1137(sc->turbo_mode == BCM2835_FIRMWARE_TURBO_ON) ? "ON":"OFF");1138}11391140/* keep in softc (MHz/mV) */1141sc->arm_max_freq = HZ2MHZ(arm_max_freq);1142sc->arm_min_freq = HZ2MHZ(arm_min_freq);1143sc->core_max_freq = HZ2MHZ(core_max_freq);1144sc->core_min_freq = HZ2MHZ(core_min_freq);1145sc->sdram_max_freq = HZ2MHZ(sdram_max_freq);1146sc->sdram_min_freq = HZ2MHZ(sdram_min_freq);1147sc->max_voltage_core = OFFSET2MVOLT(max_voltage_core);1148sc->min_voltage_core = OFFSET2MVOLT(min_voltage_core);11491150/* if turbo is on, set to max values */1151if (sc->turbo_mode == BCM2835_FIRMWARE_TURBO_ON) {1152bcm2835_cpufreq_set_clock_rate(sc,1153BCM2835_FIRMWARE_CLOCK_ID_ARM, arm_max_freq);1154DELAY(TRANSITION_LATENCY);1155bcm2835_cpufreq_set_clock_rate(sc,1156BCM2835_FIRMWARE_CLOCK_ID_CORE, core_max_freq);1157DELAY(TRANSITION_LATENCY);1158bcm2835_cpufreq_set_clock_rate(sc,1159BCM2835_FIRMWARE_CLOCK_ID_SDRAM, sdram_max_freq);1160DELAY(TRANSITION_LATENCY);1161} else {1162bcm2835_cpufreq_set_clock_rate(sc,1163BCM2835_FIRMWARE_CLOCK_ID_ARM, arm_min_freq);1164DELAY(TRANSITION_LATENCY);1165bcm2835_cpufreq_set_clock_rate(sc,1166BCM2835_FIRMWARE_CLOCK_ID_CORE, core_min_freq);1167DELAY(TRANSITION_LATENCY);1168bcm2835_cpufreq_set_clock_rate(sc,1169BCM2835_FIRMWARE_CLOCK_ID_SDRAM, sdram_min_freq);1170DELAY(TRANSITION_LATENCY);1171}11721173VC_UNLOCK(sc);11741175/* add human readable temperature to dev.cpu node */1176cpu = device_get_parent(sc->dev);1177if (cpu != NULL) {1178ctx = device_get_sysctl_ctx(cpu);1179SYSCTL_ADD_PROC(ctx,1180SYSCTL_CHILDREN(device_get_sysctl_tree(cpu)), OID_AUTO,1181"temperature",1182CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, sc, 0,1183sysctl_bcm2835_devcpu_temperature, "IK",1184"Current SoC temperature");1185}11861187/* release this hook (continue boot) */1188config_intrhook_disestablish(&sc->init_hook);1189}11901191static void1192bcm2835_cpufreq_identify(driver_t *driver, device_t parent)1193{1194const struct ofw_compat_data *compat;1195phandle_t root;11961197root = OF_finddevice("/");1198for (compat = compat_data; compat->ocd_str != NULL; compat++)1199if (ofw_bus_node_is_compatible(root, compat->ocd_str))1200break;12011202if (compat->ocd_data == 0)1203return;12041205DPRINTF("driver=%p, parent=%p\n", driver, parent);1206if (device_find_child(parent, "bcm2835_cpufreq", DEVICE_UNIT_ANY) != NULL)1207return;1208if (BUS_ADD_CHILD(parent, 0, "bcm2835_cpufreq", DEVICE_UNIT_ANY) == NULL)1209device_printf(parent, "add child failed\n");1210}12111212static int1213bcm2835_cpufreq_probe(device_t dev)1214{12151216if (device_get_unit(dev) != 0)1217return (ENXIO);1218device_set_desc(dev, "CPU Frequency Control");12191220return (0);1221}12221223static int1224bcm2835_cpufreq_attach(device_t dev)1225{1226struct bcm2835_cpufreq_softc *sc;1227struct sysctl_oid *oid;12281229/* set self dev */1230sc = device_get_softc(dev);1231sc->dev = dev;1232sc->firmware = devclass_get_device(1233devclass_find("bcm2835_firmware"), 0);1234if (sc->firmware == NULL) {1235device_printf(dev, "Unable to find firmware device\n");1236return (ENXIO);1237}12381239/* initial values */1240sc->arm_max_freq = -1;1241sc->arm_min_freq = -1;1242sc->core_max_freq = -1;1243sc->core_min_freq = -1;1244sc->sdram_max_freq = -1;1245sc->sdram_min_freq = -1;1246sc->max_voltage_core = 0;1247sc->min_voltage_core = 0;12481249/* setup sysctl at first device */1250if (device_get_unit(dev) == 0) {1251sysctl_ctx_init(&bcm2835_sysctl_ctx);1252/* create node for hw.cpufreq */1253oid = SYSCTL_ADD_NODE(&bcm2835_sysctl_ctx,1254SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, "cpufreq",1255CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "");12561257/* Frequency (Hz) */1258SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid),1259OID_AUTO, "arm_freq",1260CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0,1261sysctl_bcm2835_cpufreq_arm_freq, "IU",1262"ARM frequency (Hz)");1263SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid),1264OID_AUTO, "core_freq",1265CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0,1266sysctl_bcm2835_cpufreq_core_freq, "IU",1267"Core frequency (Hz)");1268SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid),1269OID_AUTO, "sdram_freq",1270CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0,1271sysctl_bcm2835_cpufreq_sdram_freq, "IU",1272"SDRAM frequency (Hz)");12731274/* Turbo state */1275SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid),1276OID_AUTO, "turbo",1277CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0,1278sysctl_bcm2835_cpufreq_turbo, "IU",1279"Disables dynamic clocking");12801281/* Voltage (offset from 1.2V in units of 0.025V) */1282SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid),1283OID_AUTO, "voltage_core",1284CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0,1285sysctl_bcm2835_cpufreq_voltage_core, "I",1286"ARM/GPU core voltage"1287"(offset from 1.2V in units of 0.025V)");1288SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid),1289OID_AUTO, "voltage_sdram",1290CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_NEEDGIANT, sc,12910, sysctl_bcm2835_cpufreq_voltage_sdram, "I",1292"SDRAM voltage (offset from 1.2V in units of 0.025V)");12931294/* Voltage individual SDRAM */1295SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid),1296OID_AUTO, "voltage_sdram_c",1297CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc,12980, sysctl_bcm2835_cpufreq_voltage_sdram_c, "I",1299"SDRAM controller voltage"1300"(offset from 1.2V in units of 0.025V)");1301SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid),1302OID_AUTO, "voltage_sdram_i",1303CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc,13040, sysctl_bcm2835_cpufreq_voltage_sdram_i, "I",1305"SDRAM I/O voltage (offset from 1.2V in units of 0.025V)");1306SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid),1307OID_AUTO, "voltage_sdram_p",1308CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc,13090, sysctl_bcm2835_cpufreq_voltage_sdram_p, "I",1310"SDRAM phy voltage (offset from 1.2V in units of 0.025V)");13111312/* Temperature */1313SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid),1314OID_AUTO, "temperature",1315CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, sc, 0,1316sysctl_bcm2835_cpufreq_temperature, "I",1317"SoC temperature (thousandths of a degree C)");1318}13191320/* ARM->VC lock */1321sema_init(&vc_sema, 1, "vcsema");13221323/* register callback for using mbox when interrupts are enabled */1324sc->init_hook.ich_func = bcm2835_cpufreq_init;1325sc->init_hook.ich_arg = sc;13261327if (config_intrhook_establish(&sc->init_hook) != 0) {1328device_printf(dev, "config_intrhook_establish failed\n");1329return (ENOMEM);1330}13311332/* this device is controlled by cpufreq(4) */1333cpufreq_register(dev);13341335return (0);1336}13371338static int1339bcm2835_cpufreq_detach(device_t dev)1340{13411342sema_destroy(&vc_sema);13431344return (cpufreq_unregister(dev));1345}13461347static int1348bcm2835_cpufreq_set(device_t dev, const struct cf_setting *cf)1349{1350struct bcm2835_cpufreq_softc *sc;1351uint32_t rate_hz, rem;1352int resp_freq, arm_freq, min_freq, core_freq;1353#ifdef DEBUG1354int cur_freq;1355#endif13561357if (cf == NULL || cf->freq < 0)1358return (EINVAL);13591360sc = device_get_softc(dev);13611362/* setting clock (Hz) */1363rate_hz = (uint32_t)MHZ2HZ(cf->freq);1364rem = rate_hz % HZSTEP;1365rate_hz -= rem;1366if (rate_hz == 0)1367return (EINVAL);13681369/* adjust min freq */1370min_freq = sc->arm_min_freq;1371if (sc->turbo_mode != BCM2835_FIRMWARE_TURBO_ON)1372if (min_freq > cpufreq_lowest_freq)1373min_freq = cpufreq_lowest_freq;13741375if (rate_hz < MHZ2HZ(min_freq) || rate_hz > MHZ2HZ(sc->arm_max_freq))1376return (EINVAL);13771378/* set new value and verify it */1379VC_LOCK(sc);1380#ifdef DEBUG1381cur_freq = bcm2835_cpufreq_get_clock_rate(sc,1382BCM2835_FIRMWARE_CLOCK_ID_ARM);1383#endif1384resp_freq = bcm2835_cpufreq_set_clock_rate(sc,1385BCM2835_FIRMWARE_CLOCK_ID_ARM, rate_hz);1386DELAY(TRANSITION_LATENCY);1387arm_freq = bcm2835_cpufreq_get_clock_rate(sc,1388BCM2835_FIRMWARE_CLOCK_ID_ARM);13891390/*1391* if non-turbo and lower than or equal min_freq,1392* clock down core and sdram to default first.1393*/1394if (sc->turbo_mode != BCM2835_FIRMWARE_TURBO_ON) {1395core_freq = bcm2835_cpufreq_get_clock_rate(sc,1396BCM2835_FIRMWARE_CLOCK_ID_CORE);1397if (rate_hz > MHZ2HZ(sc->arm_min_freq)) {1398bcm2835_cpufreq_set_clock_rate(sc,1399BCM2835_FIRMWARE_CLOCK_ID_CORE,1400MHZ2HZ(sc->core_max_freq));1401DELAY(TRANSITION_LATENCY);1402bcm2835_cpufreq_set_clock_rate(sc,1403BCM2835_FIRMWARE_CLOCK_ID_SDRAM,1404MHZ2HZ(sc->sdram_max_freq));1405DELAY(TRANSITION_LATENCY);1406} else {1407if (sc->core_min_freq < DEFAULT_CORE_FREQUENCY &&1408core_freq > DEFAULT_CORE_FREQUENCY) {1409/* first, down to 250, then down to min */1410DELAY(TRANSITION_LATENCY);1411bcm2835_cpufreq_set_clock_rate(sc,1412BCM2835_FIRMWARE_CLOCK_ID_CORE,1413MHZ2HZ(DEFAULT_CORE_FREQUENCY));1414DELAY(TRANSITION_LATENCY);1415/* reset core voltage */1416bcm2835_cpufreq_set_voltage(sc,1417BCM2835_FIRMWARE_VOLTAGE_ID_CORE, 0);1418DELAY(TRANSITION_LATENCY);1419}1420bcm2835_cpufreq_set_clock_rate(sc,1421BCM2835_FIRMWARE_CLOCK_ID_CORE,1422MHZ2HZ(sc->core_min_freq));1423DELAY(TRANSITION_LATENCY);1424bcm2835_cpufreq_set_clock_rate(sc,1425BCM2835_FIRMWARE_CLOCK_ID_SDRAM,1426MHZ2HZ(sc->sdram_min_freq));1427DELAY(TRANSITION_LATENCY);1428}1429}14301431VC_UNLOCK(sc);14321433if (resp_freq < 0 || arm_freq < 0 || resp_freq != arm_freq) {1434device_printf(dev, "wrong freq\n");1435return (EIO);1436}1437DPRINTF("cpufreq: %d -> %d\n", cur_freq, arm_freq);14381439return (0);1440}14411442static int1443bcm2835_cpufreq_get(device_t dev, struct cf_setting *cf)1444{1445struct bcm2835_cpufreq_softc *sc;1446int arm_freq;14471448if (cf == NULL)1449return (EINVAL);14501451sc = device_get_softc(dev);1452memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf));1453cf->dev = NULL;14541455/* get cuurent value */1456VC_LOCK(sc);1457arm_freq = bcm2835_cpufreq_get_clock_rate(sc,1458BCM2835_FIRMWARE_CLOCK_ID_ARM);1459VC_UNLOCK(sc);1460if (arm_freq < 0) {1461device_printf(dev, "can't get clock\n");1462return (EINVAL);1463}14641465/* CPU clock in MHz or 100ths of a percent. */1466cf->freq = HZ2MHZ(arm_freq);1467/* Voltage in mV. */1468cf->volts = CPUFREQ_VAL_UNKNOWN;1469/* Power consumed in mW. */1470cf->power = CPUFREQ_VAL_UNKNOWN;1471/* Transition latency in us. */1472cf->lat = TRANSITION_LATENCY;1473/* Driver providing this setting. */1474cf->dev = dev;14751476return (0);1477}14781479static int1480bcm2835_cpufreq_make_freq_list(device_t dev, struct cf_setting *sets,1481int *count)1482{1483struct bcm2835_cpufreq_softc *sc;1484int freq, min_freq, volts, rem;1485int idx;14861487sc = device_get_softc(dev);1488freq = sc->arm_max_freq;1489min_freq = sc->arm_min_freq;14901491/* adjust head freq to STEP */1492rem = freq % MHZSTEP;1493freq -= rem;1494if (freq < min_freq)1495freq = min_freq;14961497/* if non-turbo, add extra low freq */1498if (sc->turbo_mode != BCM2835_FIRMWARE_TURBO_ON)1499if (min_freq > cpufreq_lowest_freq)1500min_freq = cpufreq_lowest_freq;15011502/* XXX RPi2 have only 900/600MHz */1503idx = 0;1504volts = sc->min_voltage_core;1505sets[idx].freq = freq;1506sets[idx].volts = volts;1507sets[idx].lat = TRANSITION_LATENCY;1508sets[idx].dev = dev;1509idx++;1510if (freq != min_freq) {1511sets[idx].freq = min_freq;1512sets[idx].volts = volts;1513sets[idx].lat = TRANSITION_LATENCY;1514sets[idx].dev = dev;1515idx++;1516}1517*count = idx;15181519return (0);1520}15211522static int1523bcm2835_cpufreq_settings(device_t dev, struct cf_setting *sets, int *count)1524{1525struct bcm2835_cpufreq_softc *sc;15261527if (sets == NULL || count == NULL)1528return (EINVAL);15291530sc = device_get_softc(dev);1531if (sc->arm_min_freq < 0 || sc->arm_max_freq < 0) {1532printf("device is not configured\n");1533return (EINVAL);1534}15351536/* fill data with unknown value */1537memset(sets, CPUFREQ_VAL_UNKNOWN, sizeof(*sets) * (*count));1538/* create new array up to count */1539bcm2835_cpufreq_make_freq_list(dev, sets, count);15401541return (0);1542}15431544static int1545bcm2835_cpufreq_type(device_t dev, int *type)1546{15471548if (type == NULL)1549return (EINVAL);1550*type = CPUFREQ_TYPE_ABSOLUTE;15511552return (0);1553}15541555static device_method_t bcm2835_cpufreq_methods[] = {1556/* Device interface */1557DEVMETHOD(device_identify, bcm2835_cpufreq_identify),1558DEVMETHOD(device_probe, bcm2835_cpufreq_probe),1559DEVMETHOD(device_attach, bcm2835_cpufreq_attach),1560DEVMETHOD(device_detach, bcm2835_cpufreq_detach),15611562/* cpufreq interface */1563DEVMETHOD(cpufreq_drv_set, bcm2835_cpufreq_set),1564DEVMETHOD(cpufreq_drv_get, bcm2835_cpufreq_get),1565DEVMETHOD(cpufreq_drv_settings, bcm2835_cpufreq_settings),1566DEVMETHOD(cpufreq_drv_type, bcm2835_cpufreq_type),15671568DEVMETHOD_END1569};15701571static driver_t bcm2835_cpufreq_driver = {1572"bcm2835_cpufreq",1573bcm2835_cpufreq_methods,1574sizeof(struct bcm2835_cpufreq_softc),1575};15761577DRIVER_MODULE(bcm2835_cpufreq, cpu, bcm2835_cpufreq_driver, 0, 0);1578MODULE_DEPEND(bcm2835_cpufreq, bcm2835_firmware, 1, 1, 1);157915801581