diff options
Diffstat (limited to 'target/linux/brcm2708/patches-4.1/0017-Add-cpufreq-driver.patch')
-rw-r--r-- | target/linux/brcm2708/patches-4.1/0017-Add-cpufreq-driver.patch | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.1/0017-Add-cpufreq-driver.patch b/target/linux/brcm2708/patches-4.1/0017-Add-cpufreq-driver.patch new file mode 100644 index 0000000000..6da1856d92 --- /dev/null +++ b/target/linux/brcm2708/patches-4.1/0017-Add-cpufreq-driver.patch @@ -0,0 +1,268 @@ +From ccdc49f30be0caec97b9b7e4352b8c63eb45acdd Mon Sep 17 00:00:00 2001 +From: popcornmix <popcornmix@gmail.com> +Date: Wed, 3 Jul 2013 00:49:20 +0100 +Subject: [PATCH 017/121] Add cpufreq driver + +Signed-off-by: popcornmix <popcornmix@gmail.com> +--- + drivers/cpufreq/Kconfig.arm | 9 ++ + drivers/cpufreq/Makefile | 1 + + drivers/cpufreq/bcm2835-cpufreq.c | 224 ++++++++++++++++++++++++++++++++++++++ + 3 files changed, 234 insertions(+) + create mode 100644 drivers/cpufreq/bcm2835-cpufreq.c + +--- a/drivers/cpufreq/Kconfig.arm ++++ b/drivers/cpufreq/Kconfig.arm +@@ -258,6 +258,15 @@ config ARM_SPEAR_CPUFREQ + help + This adds the CPUFreq driver support for SPEAr SOCs. + ++config ARM_BCM2835_CPUFREQ ++ depends on BCM2708_MBOX ++ bool "BCM2835 Driver" ++ default y ++ help ++ This adds the CPUFreq driver for BCM2835 ++ ++ If in doubt, say N. ++ + config ARM_TEGRA_CPUFREQ + bool "TEGRA CPUFreq support" + depends on ARCH_TEGRA +--- a/drivers/cpufreq/Makefile ++++ b/drivers/cpufreq/Makefile +@@ -77,6 +77,7 @@ obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5p + obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o + obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o + obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o ++obj-$(CONFIG_ARM_BCM2835_CPUFREQ) += bcm2835-cpufreq.o + obj-$(CONFIG_ARM_TEGRA_CPUFREQ) += tegra-cpufreq.o + obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o + +--- /dev/null ++++ b/drivers/cpufreq/bcm2835-cpufreq.c +@@ -0,0 +1,224 @@ ++/***************************************************************************** ++* Copyright 2011 Broadcom Corporation. All rights reserved. ++* ++* Unless you and Broadcom execute a separate written software license ++* agreement governing use of this software, this software is licensed to you ++* under the terms of the GNU General Public License version 2, available at ++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). ++* ++* Notwithstanding the above, under no circumstances may you combine this ++* software in any way with any other Broadcom software provided under a ++* license other than the GPL, without Broadcom's express prior written ++* consent. ++*****************************************************************************/ ++ ++/***************************************************************************** ++* FILENAME: bcm2835-cpufreq.h ++* DESCRIPTION: This driver dynamically manages the CPU Frequency of the ARM ++* processor. Messages are sent to Videocore either setting or requesting the ++* frequency of the ARM in order to match an appropiate frequency to the current ++* usage of the processor. The policy which selects the frequency to use is ++* defined in the kernel .config file, but can be changed during runtime. ++*****************************************************************************/ ++ ++/* ---------- INCLUDES ---------- */ ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/cpufreq.h> ++#include <linux/platform_data/mailbox-bcm2708.h> ++ ++/* ---------- DEFINES ---------- */ ++/*#define CPUFREQ_DEBUG_ENABLE*/ /* enable debugging */ ++#define MODULE_NAME "bcm2835-cpufreq" ++ ++#define VCMSG_ID_ARM_CLOCK 0x000000003 /* Clock/Voltage ID's */ ++ ++/* debug printk macros */ ++#ifdef CPUFREQ_DEBUG_ENABLE ++#define print_debug(fmt,...) pr_debug("%s:%s:%d: "fmt, MODULE_NAME, __func__, __LINE__, ##__VA_ARGS__) ++#else ++#define print_debug(fmt,...) ++#endif ++#define print_err(fmt,...) pr_err("%s:%s:%d: "fmt, MODULE_NAME, __func__,__LINE__, ##__VA_ARGS__) ++#define print_info(fmt,...) pr_info("%s: "fmt, MODULE_NAME, ##__VA_ARGS__) ++ ++/* tag part of the message */ ++struct vc_msg_tag { ++ uint32_t tag_id; /* the message id */ ++ uint32_t buffer_size; /* size of the buffer (which in this case is always 8 bytes) */ ++ uint32_t data_size; /* amount of data being sent or received */ ++ uint32_t dev_id; /* the ID of the clock/voltage to get or set */ ++ uint32_t val; /* the value (e.g. rate (in Hz)) to set */ ++}; ++ ++/* message structure to be sent to videocore */ ++struct vc_msg { ++ uint32_t msg_size; /* simply, sizeof(struct vc_msg) */ ++ uint32_t request_code; /* holds various information like the success and number of bytes returned (refer to mailboxes wiki) */ ++ struct vc_msg_tag tag; /* the tag structure above to make */ ++ uint32_t end_tag; /* an end identifier, should be set to NULL */ ++}; ++ ++/* ---------- GLOBALS ---------- */ ++static struct cpufreq_driver bcm2835_cpufreq_driver; /* the cpufreq driver global */ ++ ++static struct cpufreq_frequency_table bcm2835_freq_table[] = { ++ {0, 0, 0}, ++ {0, 0, 0}, ++ {0, 0, CPUFREQ_TABLE_END}, ++}; ++ ++/* ++ =============================================== ++ clk_rate either gets or sets the clock rates. ++ =============================================== ++*/ ++static uint32_t bcm2835_cpufreq_set_clock(int cur_rate, int arm_rate) ++{ ++ int s, actual_rate=0; ++ struct vc_msg msg; ++ ++ /* wipe all previous message data */ ++ memset(&msg, 0, sizeof msg); ++ ++ msg.msg_size = sizeof msg; ++ ++ msg.tag.tag_id = VCMSG_SET_CLOCK_RATE; ++ msg.tag.buffer_size = 8; ++ msg.tag.data_size = 8; /* we're sending the clock ID and the new rates which is a total of 2 words */ ++ msg.tag.dev_id = VCMSG_ID_ARM_CLOCK; ++ msg.tag.val = arm_rate * 1000; ++ ++ /* send the message */ ++ s = bcm_mailbox_property(&msg, sizeof msg); ++ ++ /* check if it was all ok and return the rate in KHz */ ++ if (s == 0 && (msg.request_code & 0x80000000)) ++ actual_rate = msg.tag.val/1000; ++ ++ print_debug("Setting new frequency = %d -> %d (actual %d)\n", cur_rate, arm_rate, actual_rate); ++ return actual_rate; ++} ++ ++static uint32_t bcm2835_cpufreq_get_clock(int tag) ++{ ++ int s; ++ int arm_rate = 0; ++ struct vc_msg msg; ++ ++ /* wipe all previous message data */ ++ memset(&msg, 0, sizeof msg); ++ ++ msg.msg_size = sizeof msg; ++ msg.tag.tag_id = tag; ++ msg.tag.buffer_size = 8; ++ msg.tag.data_size = 4; /* we're just sending the clock ID which is one word long */ ++ msg.tag.dev_id = VCMSG_ID_ARM_CLOCK; ++ ++ /* send the message */ ++ s = bcm_mailbox_property(&msg, sizeof msg); ++ ++ /* check if it was all ok and return the rate in KHz */ ++ if (s == 0 && (msg.request_code & 0x80000000)) ++ arm_rate = msg.tag.val/1000; ++ ++ print_debug("%s frequency = %d\n", ++ tag == VCMSG_GET_CLOCK_RATE ? "Current": ++ tag == VCMSG_GET_MIN_CLOCK ? "Min": ++ tag == VCMSG_GET_MAX_CLOCK ? "Max": ++ "Unexpected", arm_rate); ++ ++ return arm_rate; ++} ++ ++/* ++ ==================================================== ++ Module Initialisation registers the cpufreq driver ++ ==================================================== ++*/ ++static int __init bcm2835_cpufreq_module_init(void) ++{ ++ print_debug("IN\n"); ++ return cpufreq_register_driver(&bcm2835_cpufreq_driver); ++} ++ ++/* ++ ============= ++ Module exit ++ ============= ++*/ ++static void __exit bcm2835_cpufreq_module_exit(void) ++{ ++ print_debug("IN\n"); ++ cpufreq_unregister_driver(&bcm2835_cpufreq_driver); ++ return; ++} ++ ++/* ++ ============================================================== ++ Initialisation function sets up the CPU policy for first use ++ ============================================================== ++*/ ++static int bcm2835_cpufreq_driver_init(struct cpufreq_policy *policy) ++{ ++ /* measured value of how long it takes to change frequency */ ++ const unsigned int transition_latency = 355000; /* ns */ ++ ++ /* now find out what the maximum and minimum frequencies are */ ++ bcm2835_freq_table[0].frequency = bcm2835_cpufreq_get_clock(VCMSG_GET_MIN_CLOCK); ++ bcm2835_freq_table[1].frequency = bcm2835_cpufreq_get_clock(VCMSG_GET_MAX_CLOCK); ++ ++ print_info("min=%d max=%d\n", bcm2835_freq_table[0].frequency, bcm2835_freq_table[1].frequency); ++ return cpufreq_generic_init(policy, bcm2835_freq_table, transition_latency); ++} ++ ++/* ++ ===================================================================== ++ Target index function chooses the requested frequency from the table ++ ===================================================================== ++*/ ++ ++static int bcm2835_cpufreq_driver_target_index(struct cpufreq_policy *policy, unsigned int state) ++{ ++ unsigned int target_freq = bcm2835_freq_table[state].frequency; ++ unsigned int cur = bcm2835_cpufreq_set_clock(policy->cur, target_freq); ++ ++ if (!cur) ++ { ++ print_err("Error occurred setting a new frequency (%d)\n", target_freq); ++ return -EINVAL; ++ } ++ print_debug("%s: %i: freq %d->%d\n", policy->governor->name, state, policy->cur, cur); ++ return 0; ++} ++ ++/* ++ ====================================================== ++ Get function returns the current frequency from table ++ ====================================================== ++*/ ++ ++static unsigned int bcm2835_cpufreq_driver_get(unsigned int cpu) ++{ ++ unsigned int actual_rate = bcm2835_cpufreq_get_clock(VCMSG_GET_CLOCK_RATE); ++ print_debug("%d: freq=%d\n", cpu, actual_rate); ++ return actual_rate <= bcm2835_freq_table[0].frequency ? bcm2835_freq_table[0].frequency : bcm2835_freq_table[1].frequency; ++} ++ ++/* the CPUFreq driver */ ++static struct cpufreq_driver bcm2835_cpufreq_driver = { ++ .name = "BCM2835 CPUFreq", ++ .init = bcm2835_cpufreq_driver_init, ++ .verify = cpufreq_generic_frequency_table_verify, ++ .target_index = bcm2835_cpufreq_driver_target_index, ++ .get = bcm2835_cpufreq_driver_get, ++ .attr = cpufreq_generic_attr, ++}; ++ ++MODULE_AUTHOR("Dorian Peake and Dom Cobley"); ++MODULE_DESCRIPTION("CPU frequency driver for BCM2835 chip"); ++MODULE_LICENSE("GPL"); ++ ++module_init(bcm2835_cpufreq_module_init); ++module_exit(bcm2835_cpufreq_module_exit); |