]>
Commit | Line | Data |
---|---|---|
723cd625 | 1 | /* |
2 | * Copyright 2011 Broadcom Corporation. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU General Public License | |
6 | * as published by the Free Software Foundation; version 2 | |
7 | * of the License. | |
8 | * | |
9 | * This driver dynamically manages the CPU Frequency of the ARM | |
10 | * processor. Messages are sent to Videocore either setting or requesting the | |
11 | * frequency of the ARM in order to match an appropiate frequency to the current | |
12 | * usage of the processor. The policy which selects the frequency to use is | |
13 | * defined in the kernel .config file, but can be changed during runtime. | |
14 | */ | |
15 | ||
16 | /* ---------- INCLUDES ---------- */ | |
17 | #include <linux/kernel.h> | |
18 | #include <linux/init.h> | |
19 | #include <linux/module.h> | |
20 | #include <linux/cpufreq.h> | |
21 | #include <soc/bcm2835/raspberrypi-firmware.h> | |
22 | ||
23 | /* ---------- DEFINES ---------- */ | |
24 | /*#define CPUFREQ_DEBUG_ENABLE*/ /* enable debugging */ | |
25 | #define MODULE_NAME "bcm2835-cpufreq" | |
26 | ||
27 | #define VCMSG_ID_ARM_CLOCK 0x000000003 /* Clock/Voltage ID's */ | |
28 | ||
29 | /* debug printk macros */ | |
30 | #ifdef CPUFREQ_DEBUG_ENABLE | |
31 | #define print_debug(fmt,...) pr_debug("%s:%s:%d: "fmt, MODULE_NAME, __func__, __LINE__, ##__VA_ARGS__) | |
32 | #else | |
33 | #define print_debug(fmt,...) | |
34 | #endif | |
35 | #define print_err(fmt,...) pr_err("%s:%s:%d: "fmt, MODULE_NAME, __func__,__LINE__, ##__VA_ARGS__) | |
36 | #define print_info(fmt,...) pr_info("%s: "fmt, MODULE_NAME, ##__VA_ARGS__) | |
37 | ||
38 | /* ---------- GLOBALS ---------- */ | |
39 | static struct cpufreq_driver bcm2835_cpufreq_driver; /* the cpufreq driver global */ | |
40 | static unsigned int min_frequency, max_frequency; | |
41 | static struct cpufreq_frequency_table bcm2835_freq_table[3]; | |
42 | ||
43 | /* | |
44 | =============================================== | |
45 | clk_rate either gets or sets the clock rates. | |
46 | =============================================== | |
47 | */ | |
48 | ||
49 | static int bcm2835_cpufreq_clock_property(u32 tag, u32 id, u32 *val) | |
50 | { | |
51 | struct rpi_firmware *fw = rpi_firmware_get(NULL); | |
52 | struct { | |
53 | u32 id; | |
54 | u32 val; | |
55 | } packet; | |
56 | int ret; | |
57 | ||
58 | packet.id = id; | |
59 | packet.val = *val; | |
60 | ret = rpi_firmware_property(fw, tag, &packet, sizeof(packet)); | |
61 | if (ret) | |
62 | return ret; | |
63 | ||
64 | *val = packet.val; | |
65 | ||
66 | return 0; | |
67 | } | |
68 | ||
69 | static uint32_t bcm2835_cpufreq_set_clock(int cur_rate, int arm_rate) | |
70 | { | |
71 | u32 rate = arm_rate * 1000; | |
72 | int ret; | |
73 | ||
74 | ret = bcm2835_cpufreq_clock_property(RPI_FIRMWARE_SET_CLOCK_RATE, VCMSG_ID_ARM_CLOCK, &rate); | |
75 | if (ret) { | |
76 | print_err("Failed to set clock: %d (%d)\n", arm_rate, ret); | |
77 | return 0; | |
78 | } | |
79 | ||
80 | rate /= 1000; | |
81 | print_debug("Setting new frequency = %d -> %d (actual %d)\n", cur_rate, arm_rate, rate); | |
82 | ||
83 | return rate; | |
84 | } | |
85 | ||
86 | static uint32_t bcm2835_cpufreq_get_clock(int tag) | |
87 | { | |
88 | u32 rate; | |
89 | int ret; | |
90 | ||
91 | ret = bcm2835_cpufreq_clock_property(tag, VCMSG_ID_ARM_CLOCK, &rate); | |
92 | if (ret) { | |
93 | print_err("Failed to get clock (%d)\n", ret); | |
94 | return 0; | |
95 | } | |
96 | ||
97 | rate /= 1000; | |
98 | print_debug("%s frequency = %u\n", | |
99 | tag == RPI_FIRMWARE_GET_CLOCK_RATE ? "Current": | |
100 | tag == RPI_FIRMWARE_GET_MIN_CLOCK_RATE ? "Min": | |
101 | tag == RPI_FIRMWARE_GET_MAX_CLOCK_RATE ? "Max": | |
102 | "Unexpected", rate); | |
103 | ||
104 | return rate; | |
105 | } | |
106 | ||
107 | /* | |
108 | ==================================================== | |
109 | Module Initialisation registers the cpufreq driver | |
110 | ==================================================== | |
111 | */ | |
112 | static int __init bcm2835_cpufreq_module_init(void) | |
113 | { | |
114 | print_debug("IN\n"); | |
115 | return cpufreq_register_driver(&bcm2835_cpufreq_driver); | |
116 | } | |
117 | ||
118 | /* | |
119 | ============= | |
120 | Module exit | |
121 | ============= | |
122 | */ | |
123 | static void __exit bcm2835_cpufreq_module_exit(void) | |
124 | { | |
125 | print_debug("IN\n"); | |
126 | cpufreq_unregister_driver(&bcm2835_cpufreq_driver); | |
127 | return; | |
128 | } | |
129 | ||
130 | /* | |
131 | ============================================================== | |
132 | Initialisation function sets up the CPU policy for first use | |
133 | ============================================================== | |
134 | */ | |
135 | static int bcm2835_cpufreq_driver_init(struct cpufreq_policy *policy) | |
136 | { | |
137 | /* measured value of how long it takes to change frequency */ | |
138 | const unsigned int transition_latency = 355000; /* ns */ | |
139 | ||
140 | if (!rpi_firmware_get(NULL)) { | |
141 | print_err("Firmware is not available\n"); | |
142 | return -ENODEV; | |
143 | } | |
144 | ||
145 | /* now find out what the maximum and minimum frequencies are */ | |
146 | min_frequency = bcm2835_cpufreq_get_clock(RPI_FIRMWARE_GET_MIN_CLOCK_RATE); | |
147 | max_frequency = bcm2835_cpufreq_get_clock(RPI_FIRMWARE_GET_MAX_CLOCK_RATE); | |
148 | ||
149 | if (min_frequency == max_frequency) { | |
150 | bcm2835_freq_table[0].frequency = min_frequency; | |
151 | bcm2835_freq_table[1].frequency = CPUFREQ_TABLE_END; | |
152 | } else { | |
153 | bcm2835_freq_table[0].frequency = min_frequency; | |
154 | bcm2835_freq_table[1].frequency = max_frequency; | |
155 | bcm2835_freq_table[2].frequency = CPUFREQ_TABLE_END; | |
156 | } | |
157 | ||
158 | print_info("min=%d max=%d\n", min_frequency, max_frequency); | |
159 | return cpufreq_generic_init(policy, bcm2835_freq_table, transition_latency); | |
160 | } | |
161 | ||
162 | /* | |
163 | ===================================================================== | |
164 | Target index function chooses the requested frequency from the table | |
165 | ===================================================================== | |
166 | */ | |
167 | ||
168 | static int bcm2835_cpufreq_driver_target_index(struct cpufreq_policy *policy, unsigned int state) | |
169 | { | |
170 | unsigned int target_freq = state == 0 ? min_frequency : max_frequency; | |
171 | unsigned int cur = bcm2835_cpufreq_set_clock(policy->cur, target_freq); | |
172 | ||
173 | if (!cur) | |
174 | { | |
175 | print_err("Error occurred setting a new frequency (%d)\n", target_freq); | |
176 | return -EINVAL; | |
177 | } | |
178 | print_debug("%s: %i: freq %d->%d\n", policy->governor->name, state, policy->cur, cur); | |
179 | return 0; | |
180 | } | |
181 | ||
182 | /* | |
183 | ====================================================== | |
184 | Get function returns the current frequency from table | |
185 | ====================================================== | |
186 | */ | |
187 | ||
188 | static unsigned int bcm2835_cpufreq_driver_get(unsigned int cpu) | |
189 | { | |
190 | unsigned int actual_rate = bcm2835_cpufreq_get_clock(RPI_FIRMWARE_GET_CLOCK_RATE); | |
191 | print_debug("cpu%d: freq=%d\n", cpu, actual_rate); | |
192 | return actual_rate <= min_frequency ? min_frequency : max_frequency; | |
193 | } | |
194 | ||
195 | /* the CPUFreq driver */ | |
196 | static struct cpufreq_driver bcm2835_cpufreq_driver = { | |
197 | .name = "BCM2835 CPUFreq", | |
198 | .init = bcm2835_cpufreq_driver_init, | |
199 | .verify = cpufreq_generic_frequency_table_verify, | |
200 | .target_index = bcm2835_cpufreq_driver_target_index, | |
201 | .get = bcm2835_cpufreq_driver_get, | |
202 | .attr = cpufreq_generic_attr, | |
203 | }; | |
204 | ||
205 | MODULE_AUTHOR("Dorian Peake and Dom Cobley"); | |
206 | MODULE_DESCRIPTION("CPU frequency driver for BCM2835 chip"); | |
207 | MODULE_LICENSE("GPL"); | |
208 | ||
209 | module_init(bcm2835_cpufreq_module_init); | |
210 | module_exit(bcm2835_cpufreq_module_exit); |