Hello! I am currently trying to compile my own kernel with Smartass governor and Higher CPU frequencies for my MyTouch 4G Slide. I successfully compiled my own kernel from the HTC Source but now have ran into a problem... I am trying to compile my own Smartass module from the source I found Here but unfortunately this being my first kernel I have no idea how... Whenever I try to compile the module gives me an error..
Im guessing its related to the line
"#define OFS_KALLSYMS_LOOKUP_NAME 0xc009684c // kallsyms_lookup_name"
but not sure... How would I find this address? How do I incorporate the governor after I compile the module successfully?
Thanks in advanced!
~GiGoO
gigoo25 said:
Hello! I am currently trying to compile my own kernel with Smartass governor and Higher CPU frequencies for my MyTouch 4G Slide. I successfully compiled my own kernel from the HTC Source but now have ran into a problem... I am trying to compile my own Smartass module from the source I found Here but unfortunately this being my first kernel I have no idea how... Whenever I try to compile the module gives me an error..
Im guessing its related to the line
"#define OFS_KALLSYMS_LOOKUP_NAME 0xc009684c // kallsyms_lookup_name"
but not sure... How would I find this address? How do I incorporate the governor after I compile the module successfully?
Thanks in advanced!
~GiGoO
Click to expand...
Click to collapse
Okay, the advice I am going to give you is contrary to what you hear about working on kernels - I am going to tell you not to try to make a new module, but to edit the source directly.
in .../arch/arm/mach-msm/acpuclock-8x60.c you will find the primary cpu table for clock speed.
You will notice here and elsewhere scattered throughout the kernel source that HTC made a mess of things - they originally had programmed the kernel to support the chip to it's rated speed of 1.5...and then somewhere along the way changed their minds and brought it down to 1.2.
Now we have scattered references to the 1.5 clock speed throughout kernel source, and so in order to mess with clock speed directly you will need to clean up these leftovers we have floating around.
In the file I mentioned above, you can get your start - but instead of trying to add a module to the kernel it's better in this case to work with it directly.
If someone gets a clean version of the code set and ready for us that we could build from, then maybe adding modules would be more successful - as it's technically the correct way to do what you are trying.
You happen to be working on exactly the same thing I am working on right this very minute, so that's fortunate in regards to your question I suppose. I'm glad to see someone else putting time into kernel work for this device.
Hope this helps you out, even though it's not what you want to hear.
Blue6IX said:
Okay, the advice I am going to give you is contrary to what you hear about working on kernels - I am going to tell you not to try to make a new module, but to edit the source directly.
in .../arch/arm/mach-msm/acpuclock-8x60.c you will find the primary cpu table for clock speed.
You will notice here and elsewhere scattered throughout the kernel source that HTC made a mess of things - they originally had programmed the kernel to support the chip to it's rated speed of 1.5...and then somewhere along the way changed their minds and brought it down to 1.2.
Now we have scattered references to the 1.5 clock speed throughout kernel source, and so in order to mess with clock speed directly you will need to clean up these leftovers we have floating around.
In the file I mentioned above, you can get your start - but instead of trying to add a module to the kernel it's better in this case to work with it directly.
If someone gets a clean version of the code set and ready for us that we could build from, then maybe adding modules would be more successful - as it's technically the correct way to do what you are trying.
You happen to be working on exactly the same thing I am working on right this very minute, so that's fortunate in regards to your question I suppose. I'm glad to see someone else putting time into kernel work for this device.
Hope this helps you out, even though it's not what you want to hear.
Click to expand...
Click to collapse
Thanks for the quick reply!
So in order to add more frequencies you would have to edit "acpuclock-8x60.c" and what some other files in the same directory correct?
Yea, i've been digging through kernel source for a while now, but only off and on - i'm just now starting to focus more attention on it. I don't think i've isolated everywhere the clock speed is defined, but that cpu table is the primary reference point.
Sent from my NookColor using xda premium
Just out of curiosity, what about acpuclock-arm11.c in the same folder?
blackknightavalon said:
Just out of curiosity, what about acpuclock-arm11.c in the same folder?
Click to expand...
Click to collapse
Shouldn't have any effect. Arm11 architecture topped out at 1Ghz I believe, single core only.
A bit of a dated product specification, considering we are running over 1Ghz and dual core.
Edit:
Ever seen the movie hackers? (lol...as if I have to ask) remeber when they are in burns bedroom and they are talking about risc architecture, and how it will change everything?
(reduced instruction set computing)
Well, they were right - and when the ARM-7 series of processors hit it had about the same effect on the portable digital world. They worked their way up to ARM-9 then 11, but I think that was the end of the ARM line, at least as much as I remember reading up on.
1 Ghz is basically ancient tech in today's world.
My guess is your both working on a sense/mysense 3.0 kernel....once you get that how hard would it be to upgrade to sense 3.5 compatibility?
To be flat-out honest with you, I have no idea.
I don't know what the difference is. Being a newcomer to Android, and not knowing what Sense was before purchasing this device at the beginning of august, i'm still learning about it all.
I suppose that may surprise some people to learn, but I don't BS around with pretending to know more then I do. That only leads to not learning what I should, and spreading false or inaccurate information. There are a lot of posts around here I want to respond to but can't for lack of information, and even spending literally around the clock learning Android there is a whole lot I haven't yet.
I can work with what's right in front of me and in my hand, reverse engineer it and take it apart to tinker and find out how it works, but if I don't have it it's outside of my sphere of learning at the moment.
If you could expand on the technical details and differences between 3.0 and 3.5 I could give you a better answer.
Blue6IX said:
To be flat-out honest with you, I have no idea.
I don't know what the difference is. Being a newcomer to Android, and not knowing what Sense was before purchasing this device at the beginning of august, i'm still learning about it all.
I suppose that may surprise some people to learn, but I don't BS around with pretending to know more then I do. That only leads to not learning what I should, and spreading false or inaccurate information. There are a lot of posts around here I want to respond to but can't for lack of information, and even spending literally around the clock learning Android there is a whole lot I haven't yet.
I can work with what's right in front of me and in my hand, reverse engineer it and take it apart to tinker and find out how it works, but if I don't have it it's outside of my sphere of learning at the moment.
If you could expand on the technical details and differences between 3.0 and 3.5 I could give you a better answer.
Click to expand...
Click to collapse
IN all actuality I don't believe there is a whole big difference between the two...basically more visual....cleaned up improvements to Sense 3.0....my guess is when HTC releases a phone with ICS it might even have a whole new sense release...but 3.5 is so new....hard to tell....there is only a few phones out with 3.5...where are you learning your coding from...I can try and learn..i have very minimal python coding experience so would be like learning Chinese I imagine...I excel more on beta testing...i can take something and run it hard through paces...coding....not so much....I am an inside the box kind of thinker...lol
beezie916 said:
IN all actuality I don't believe there is a whole big difference between the two...basically more visual....cleaned up improvements to Sense 3.0....my guess is when HTC releases a phone with ICS it might even have a whole new sense release...but 3.5 is so new....hard to tell....there is only a few phones out with 3.5...where are you learning your coding from...I can try and learn..i have very minimal python coding experience so would be like learning Chinese I imagine...I excel more on beta testing...i can take something and run it hard through paces...coding....not so much....I am an inside the box kind of thinker...lol
Click to expand...
Click to collapse
a lifetime of tinkering with stuff on computers, everything i've learned about Android has been right here at XDA.
The best place to start learning to code is learn HTML. Yea - that's it right there.
If you can learn HTML, you can learn any human-readable programming language.
If you want to learn to make Android apps, you need to know java. If you want to learn to code kernels, you need to learn C flavor languages.
After you play with a few higher level programming languages you learn they are all the same - the only difference is syntax.
Blue6IX said:
a lifetime of tinkering with stuff on computers, everything i've learned about Android has been right here at XDA.
The best place to start learning to code is learn HTML. Yea - that's it right there.
If you can learn HTML, you can learn any human-readable programming language.
If you want to learn to make Android apps, you need to know java. If you want to learn to code kernels, you need to learn C flavor languages.
After you play with a few higher level programming languages you learn they are all the same - the only difference is syntax.
Click to expand...
Click to collapse
Well I have been messing around with it and ended up editing "acpuclock-8x60" here is the final product...
Code:
/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/cpufreq.h>
#include <linux/cpu.h>
#include <linux/regulator/consumer.h>
#include <asm/cpu.h>
#include <mach/board.h>
#include <mach/msm_iomap.h>
#include <mach/msm_bus.h>
#include <mach/msm_bus_board.h>
#include <mach/socinfo.h>
#include "acpuclock.h"
#include "clock-8x60.h"
#include "rpm-regulator.h"
#include "avs.h"
#define dprintk(msg...) \
cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "cpufreq-msm", msg)
/* Frequency switch modes. */
#define SHOT_SWITCH 4
#define HOP_SWITCH 5
#define SIMPLE_SLEW 6
#define COMPLEX_SLEW 7
/* PLL calibration limits.
* The PLL hardware is capable of 384MHz to 1536MHz. The L_VALs
* used for calibration should respect these limits. */
#define L_VAL_SCPLL_CAL_MIN 0x08 /* = 432 MHz with 27MHz source */
#define L_VAL_SCPLL_CAL_MAX 0x1C /* = 1512 MHz with 27MHz source */
#define MAX_VDD_SC 1250000 /* uV */
#define MAX_AXI 310500 /* KHz */
#define SCPLL_LOW_VDD_FMAX 594000 /* KHz */
#define SCPLL_LOW_VDD 1000000 /* uV */
#define SCPLL_NOMINAL_VDD 1100000 /* uV */
/* SCPLL Modes. */
#define SCPLL_POWER_DOWN 0
#define SCPLL_BYPASS 1
#define SCPLL_STANDBY 2
#define SCPLL_FULL_CAL 4
#define SCPLL_HALF_CAL 5
#define SCPLL_STEP_CAL 6
#define SCPLL_NORMAL 7
#define SCPLL_DEBUG_NONE 0
#define SCPLL_DEBUG_FULL 3
/* SCPLL registers offsets. */
#define SCPLL_DEBUG_OFFSET 0x0
#define SCPLL_CTL_OFFSET 0x4
#define SCPLL_CAL_OFFSET 0x8
#define SCPLL_STATUS_OFFSET 0x10
#define SCPLL_CFG_OFFSET 0x1C
#define SCPLL_FSM_CTL_EXT_OFFSET 0x24
#define SCPLL_LUT_A_HW_MAX (0x38 + ((L_VAL_SCPLL_CAL_MAX / 4) * 4))
/* Clock registers. */
#define SPSS0_CLK_CTL_ADDR (MSM_ACC0_BASE + 0x04)
#define SPSS0_CLK_SEL_ADDR (MSM_ACC0_BASE + 0x08)
#define SPSS1_CLK_CTL_ADDR (MSM_ACC1_BASE + 0x04)
#define SPSS1_CLK_SEL_ADDR (MSM_ACC1_BASE + 0x08)
#define SPSS_L2_CLK_SEL_ADDR (MSM_GCC_BASE + 0x38)
/* Speed bin register. */
#define QFPROM_SPEED_BIN_ADDR (MSM_QFPROM_BASE + 0x00C0)
static const void * const clk_ctl_addr[] = {SPSS0_CLK_CTL_ADDR,
SPSS1_CLK_CTL_ADDR};
static const void * const clk_sel_addr[] = {SPSS0_CLK_SEL_ADDR,
SPSS1_CLK_SEL_ADDR, SPSS_L2_CLK_SEL_ADDR};
static const int rpm_vreg_voter[] = { RPM_VREG_VOTER1, RPM_VREG_VOTER2 };
static struct regulator *regulator_sc[NR_CPUS];
enum scplls {
CPU0 = 0,
CPU1,
L2,
};
static const void * const sc_pll_base[] = {
[CPU0] = MSM_SCPLL_BASE + 0x200,
[CPU1] = MSM_SCPLL_BASE + 0x300,
[L2] = MSM_SCPLL_BASE + 0x400,
};
enum sc_src {
ACPU_AFAB,
ACPU_PLL_8,
ACPU_SCPLL,
};
static struct clock_state {
struct clkctl_acpu_speed *current_speed[NR_CPUS];
struct clkctl_l2_speed *current_l2_speed;
spinlock_t l2_lock;
struct mutex lock;
uint32_t acpu_switch_time_us;
uint32_t vdd_switch_time_us;
uint32_t max_speed_delta_khz;
} drv_state;
struct clkctl_l2_speed {
unsigned int khz;
unsigned int src_sel;
unsigned int l_val;
unsigned int vdd_dig;
unsigned int vdd_mem;
unsigned int bw_level;
};
static struct clkctl_l2_speed *l2_vote[NR_CPUS];
struct clkctl_acpu_speed {
unsigned int use_for_scaling[2]; /* One for each CPU. */
unsigned int acpuclk_khz;
int pll;
unsigned int acpuclk_src_sel;
unsigned int acpuclk_src_div;
unsigned int core_src_sel;
unsigned int l_val;
struct clkctl_l2_speed *l2_level;
unsigned int vdd_sc;
unsigned int avsdscr_setting;
};
/* Instantaneous bandwidth requests in MB/s. */
#define BW_MBPS(_bw) \
{ \
.vectors = &(struct msm_bus_vectors){ \
.src = MSM_BUS_MASTER_AMPSS_M0, \
.dst = MSM_BUS_SLAVE_EBI_CH0, \
.ib = (_bw) * 1000000UL, \
.ab = 0, \
}, \
.num_paths = 1, \
}
static struct msm_bus_paths bw_level_tbl[] = {
[0] = BW_MBPS(824), /* At least 103 MHz on bus. */
[1] = BW_MBPS(1336), /* At least 167 MHz on bus. */
[2] = BW_MBPS(2008), /* At least 251 MHz on bus. */
[3] = BW_MBPS(2480), /* At least 310 MHz on bus. */
};
static struct msm_bus_scale_pdata bus_client_pdata = {
.usecase = bw_level_tbl,
.num_usecases = ARRAY_SIZE(bw_level_tbl),
.active_only = 1,
.name = "acpuclock",
};
static uint32_t bus_perf_client;
/* L2 frequencies = 2 * 27 MHz * L_VAL */
static struct clkctl_l2_speed l2_freq_tbl_v2[] = {
[0] = { MAX_AXI, 0, 0, 1000000, 1100000, 0},
[1] = { 245760, 1, 0x09, 1000000, 1100000, 0},
[2] = { 368640, 1, 0x0A, 1000000, 1100000, 0},
[3] = { 768000, 1, 0x0B, 1100000, 1100000, 0},
[4] = { 806400, 1, 0x0C, 1100000, 1100000, 0},
[5] = { 825600, 1, 0x0D, 1100000, 1100000, 0},
[6] = { 844800, 1, 0x0E, 1100000, 1100000, 1},
[7] = { 864000, 1, 0x0F, 1100000, 1100000, 1},
[8] = { 883200, 1, 0x10, 1100000, 1100000, 1},
[9] = { 902400, 1, 0x11, 1100000, 1100000, 1},
[10] = { 921600, 1, 0x12, 1100000, 1100000, 1},
[11] = { 940800, 1, 0x13, 1100000, 1100000, 2},
[12] = { 960000, 1, 0x14, 1100000, 1100000, 2},
[13] = { 979200, 1, 0x15, 1100000, 1100000, 2},
[14] = { 998400, 1, 0x16, 1100000, 1100000, 2},
[15] = {1017600, 1, 0X1A, 1100000, 1100000, 2},
[16] = {1036800, 1, 0x1B, 1100000, 1200000, 3},
[17] = {1056000, 1, 0x1C, 1100000, 1200000, 3},
[18] = {1075200, 1, 0x1D, 1100000, 1200000, 3},
[19] = {1094400, 1, 0x1E, 1100000, 1200000, 3},
[20] = {1209600, 1, 0x1F, 1100000, 1200000, 3},
[21] = {1248000, 1, 0x20, 1100000, 1200000, 4},
[22] = {1267200, 1, 0x21, 1100000, 1200000, 4},
[23] = {1286400, 1, 0x22, 1100000, 1200000, 4},
[24] = {1305600, 1, 0x23, 1100000, 1200000, 4},
[25] = {1344000, 1, 0x24, 1100000, 1200000, 4},
[26] = {1363200, 1, 0x25, 1100000, 1200000, 5},
[27] = {1382400, 1, 0x26, 1200000, 1200000, 5},
[28] = {1401600, 1, 0x2A, 1200000, 1250000, 5},
[29] = {1459200, 1, 0x2B, 1200000, 1250000, 5},
[30] = {1512000, 1, 0x2C, 1250000, 1250000, 5},
};
#define L2(x) (&l2_freq_tbl_v2[(x)])
/* SCPLL frequencies = 2 * 27 MHz * L_VAL */
static struct clkctl_acpu_speed acpu_freq_tbl_v2[] = {
{ {1, 1}, 192000, ACPU_PLL_8, 3, 1, 0, 0, L2(1), 812500, 0x03006000},
/* MAX_AXI row is used to source CPU cores and L2 from the AFAB clock. */
{ {0, 0}, MAX_AXI, ACPU_AFAB, 1, 0, 0, 0, L2(0), 812500, 0x03006000},
{ {1, 1}, 245760, ACPU_PLL_8, 3, 0, 0, 0, L2(1), 850000, 0x03006000},
{ {1, 1}, 368640, ACPU_SCPLL, 0, 0, 0, 0x09, L2(2), 875000, 0x03006000},
{ {1, 1}, 768000, ACPU_SCPLL, 0, 0, 1, 0x0A, L2(3), 975000, 0x03006000},
{ {1, 1}, 806400, ACPU_SCPLL, 0, 0, 1, 0x0B, L2(4), 975000, 0x03006000},
{ {1, 1}, 825600, ACPU_SCPLL, 0, 0, 1, 0x0C, L2(5), 1032500, 0x03006000},
{ {1, 1}, 844800, ACPU_SCPLL, 0, 0, 1, 0x0D, L2(6), 1035000, 0x03006000},
{ {1, 1}, 864000, ACPU_SCPLL, 0, 0, 1, 0x0E, L2(7), 1037500, 0x03006000},
{ {1, 1}, 883200, ACPU_SCPLL, 0, 0, 1, 0x0F, L2(8), 1042500, 0x03006000},
{ {1, 1}, 902400, ACPU_SCPLL, 0, 0, 1, 0x10, L2(9), 1060000, 0x03006000},
{ {1, 1}, 921600, ACPU_SCPLL, 0, 0, 1, 0x11, L2(10), 1062500, 0x03006000},
{ {1, 1}, 940800, ACPU_SCPLL, 0, 0, 1, 0x12, L2(11), 1065000, 0x03006000},
{ {1, 1}, 960000, ACPU_SCPLL, 0, 0, 1, 0x13, L2(12), 1067500, 0x03006000},
{ {1, 1}, 979200, ACPU_SCPLL, 0, 0, 1, 0x14, L2(13), 1087500, 0x03006000},
{ {1, 1}, 998400, ACPU_SCPLL, 0, 0, 1, 0x15, L2(14), 1100000, 0x03006000},
{ {1, 1}, 1017600, ACPU_SCPLL, 0, 0, 1, 0x16, L2(15), 1125000, 0x03006000},
{ {1, 1}, 1036800, ACPU_SCPLL, 0, 0, 1, 0x1A, L2(16), 1125000, 0x03006000},
{ {1, 1}, 1056000, ACPU_SCPLL, 0, 0, 1, 0x1B, L2(17), 1150000, 0x03006000},
{ {1, 1}, 1075200, ACPU_SCPLL, 0, 0, 1, 0x1C, L2(18), 1135000, 0x03006000},
{ {1, 1}, 1094400, ACPU_SCPLL, 0, 0, 1, 0x1D, L2(19), 1137500, 0x03006000},
{ {1, 1}, 1209600, ACPU_SCPLL, 0, 0, 1, 0x1E, L2(20), 1190000, 0x03006000},
{ {1, 1}, 1248000, ACPU_SCPLL, 0, 0, 1, 0x20, L2(21), 1195000, 0x03006000},
{ {1, 1}, 1267200, ACPU_SCPLL, 0, 0, 1, 0x21, L2(22), 1195000, 0x03006000},
{ {1, 1}, 1286400, ACPU_SCPLL, 0, 0, 1, 0x22, L2(23), 1195000, 0x03006000},
{ {1, 1}, 1305600, ACPU_SCPLL, 0, 0, 1, 0x23, L2(24), 1195000, 0x03006000},
{ {1, 1}, 1344000, ACPU_SCPLL, 0, 0, 1, 0x25, L2(25), 1195000, 0x03006000},
{ {1, 1}, 1363200, ACPU_SCPLL, 0, 0, 1, 0x26, L2(26), 1197500, 0x03006000},
{ {1, 1}, 1382400, ACPU_SCPLL, 0, 0, 1, 0x2A, L2(27), 1200000, 0x03006000},
{ {1, 1}, 1401600, ACPU_SCPLL, 0, 0, 1, 0x2B, L2(28), 1225000, 0x03006000},
{ {1, 1}, 1459200, ACPU_SCPLL, 0, 0, 1, 0x2C, L2(29), 1225000, 0x03006000},
{ {1, 1}, 1512000, ACPU_SCPLL, 0, 0, 1, 0x2D, L2(30), 1250000, 0x03006000},
{ {0, 0}, 0 },
};
/* acpu_freq_tbl row to use when reconfiguring SC/L2 PLLs. */
#define CAL_IDX 1
static struct clkctl_acpu_speed *acpu_freq_tbl;
static struct clkctl_l2_speed *l2_freq_tbl;
static unsigned int l2_freq_tbl_size;
unsigned long acpuclk_get_rate(int cpu)
{
return drv_state.current_speed[cpu]->acpuclk_khz;
}
uint32_t acpuclk_get_switch_time(void)
{
return drv_state.acpu_switch_time_us;
}
unsigned long clk_get_max_axi_khz(void)
{
return MAX_AXI;
}
EXPORT_SYMBOL(clk_get_max_axi_khz);
#define POWER_COLLAPSE_KHZ MAX_AXI
unsigned long acpuclk_power_collapse(void)
{
int ret = acpuclk_get_rate(smp_processor_id());
acpuclk_set_rate(smp_processor_id(), POWER_COLLAPSE_KHZ, SETRATE_PC);
return ret;
}
#define WAIT_FOR_IRQ_KHZ MAX_AXI
unsigned long acpuclk_wait_for_irq(void)
{
int ret = acpuclk_get_rate(smp_processor_id());
acpuclk_set_rate(smp_processor_id(), WAIT_FOR_IRQ_KHZ, SETRATE_SWFI);
return ret;
}
static void select_core_source(unsigned int id, unsigned int src)
{
uint32_t regval;
int shift;
shift = (id == L2) ? 0 : 1;
regval = readl(clk_sel_addr[id]);
regval &= ~(0x3 << shift);
regval |= (src << shift);
writel(regval, clk_sel_addr[id]);
}
static void select_clk_source_div(unsigned int id, struct clkctl_acpu_speed *s)
{
uint32_t reg_clksel, reg_clkctl, src_sel;
/* Configure the PLL divider mux if we plan to use it. */
if (s->core_src_sel == 0) {
reg_clksel = readl(clk_sel_addr[id]);
/* CLK_SEL_SRC1N0 (bank) bit. */
src_sel = reg_clksel & 1;
/* Program clock source and divider. */
reg_clkctl = readl(clk_ctl_addr[id]);
reg_clkctl &= ~(0xFF << (8 * src_sel));
reg_clkctl |= s->acpuclk_src_sel << (4 + 8 * src_sel);
reg_clkctl |= s->acpuclk_src_div << (0 + 8 * src_sel);
writel(reg_clkctl, clk_ctl_addr[id]);
/* Toggle clock source. */
reg_clksel ^= 1;
/* Program clock source selection. */
writel(reg_clksel, clk_sel_addr[id]);
}
}
static void scpll_enable(int sc_pll, uint32_t l_val)
{
uint32_t regval;
/* Power-up SCPLL into standby mode. */
writel(SCPLL_STANDBY, sc_pll_base[sc_pll] + SCPLL_CTL_OFFSET);
dsb();
udelay(10);
/* Shot-switch to target frequency. */
regval = (l_val << 3) | SHOT_SWITCH;
writel(regval, sc_pll_base[sc_pll] + SCPLL_FSM_CTL_EXT_OFFSET);
writel(SCPLL_NORMAL, sc_pll_base[sc_pll] + SCPLL_CTL_OFFSET);
dsb();
udelay(20);
}
static void scpll_check_ico(int sc_pll)
{
uint32_t regval;
regval = readl(sc_pll_base[sc_pll] + SCPLL_CTL_OFFSET);
if (regval & BIT(18)) {
dprintk("SCPLL%d: ICO2 set before scpll_disable. Register=%d\n",
sc_pll, regval);
}
}
static void scpll_disable(int sc_pll)
{
scpll_check_ico(sc_pll);
/* Power down SCPLL. */
writel(SCPLL_POWER_DOWN, sc_pll_base[sc_pll] + SCPLL_CTL_OFFSET);
}
#ifdef CONFIG_ACPUCLK_SET_RATE_DEBUG
#define SETRATE_TIMEOUT (3 * HZ)
struct task_struct *set_rate_process;
static void set_rate_timeout_handler(unsigned long data)
{
struct task_struct *g, *p;
pr_info("acpuclk_set_rate timeout, print stack\n");
read_lock(&tasklist_lock);
do_each_thread(g, p) {
if (p == set_rate_process )
sched_show_task(set_rate_process);
} while_each_thread(g, p);
read_unlock(&tasklist_lock);
pr_info("Blocked tasks\n");
show_state_filter(TASK_UNINTERRUPTIBLE);
}
static DEFINE_TIMER(set_rate_timer, set_rate_timeout_handler, 0, 0);
#endif
static void scpll_change_freq(int sc_pll, uint32_t l_val)
{
uint32_t regval;
const void *base_addr = sc_pll_base[sc_pll];
/* Complex-slew switch to target frequency. */
regval = (l_val << 3) | COMPLEX_SLEW;
writel(regval, base_addr + SCPLL_FSM_CTL_EXT_OFFSET);
writel(SCPLL_NORMAL, base_addr + SCPLL_CTL_OFFSET);
/* Wait for frequency switch to start. */
while (((readl(base_addr + SCPLL_CTL_OFFSET) >> 3) & 0x3F) != l_val)
cpu_relax();
/* Wait for frequency switch to finish. */
while (readl(base_addr + SCPLL_STATUS_OFFSET) & 0x1)
cpu_relax();
}
/* Vote for the L2 speed and return the speed that should be applied. */
static struct clkctl_l2_speed *compute_l2_speed(unsigned int voting_cpu,
struct clkctl_l2_speed *tgt_s)
{
struct clkctl_l2_speed *new_s;
int cpu;
/* Bounds check. */
BUG_ON(tgt_s >= (l2_freq_tbl + l2_freq_tbl_size));
/* Find max L2 speed vote. */
l2_vote[voting_cpu] = tgt_s;
new_s = l2_freq_tbl;
for_each_present_cpu(cpu)
new_s = max(new_s, l2_vote[cpu]);
return new_s;
}
/* Set the L2's clock speed. */
static void set_l2_speed(struct clkctl_l2_speed *tgt_s)
{
if (tgt_s == drv_state.current_l2_speed)
return;
if (drv_state.current_l2_speed->src_sel == 1
&& tgt_s->src_sel == 1)
scpll_change_freq(L2, tgt_s->l_val);
else {
if (tgt_s->src_sel == 1) {
scpll_enable(L2, tgt_s->l_val);
dsb();
select_core_source(L2, tgt_s->src_sel);
} else {
select_core_source(L2, tgt_s->src_sel);
dsb();
scpll_disable(L2);
}
}
drv_state.current_l2_speed = tgt_s;
}
/* Update the bus bandwidth request. */
static void set_bus_bw(unsigned int bw)
{
int ret;
/* Bounds check. */
if (bw >= ARRAY_SIZE(bw_level_tbl)) {
pr_err("%s: invalid bandwidth request (%d)\n", __func__, bw);
return;
}
/* Update bandwidth if requst has changed. */
ret = msm_bus_scale_client_update_request(bus_perf_client, bw);
if (ret)
pr_err("%s: bandwidth request failed (%d)\n", __func__, ret);
return;
}
/* Apply any per-cpu voltage increases. */
static int increase_vdd(int cpu, unsigned int vdd_sc, unsigned int vdd_mem,
unsigned int vdd_dig)
{
int rc = 0;
/* Increase vdd_mem active-set before vdd_dig and vdd_sc.
* vdd_mem should be >= both vdd_sc and vdd_dig. */
rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8058_S0,
rpm_vreg_voter[cpu], vdd_mem, 0);
if (rc) {
pr_err("%s: vdd_mem (cpu%d) increase failed (%d)\n",
__func__, cpu, rc);
return rc;
}
/* Increase vdd_dig active-set vote. */
rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8058_S1,
rpm_vreg_voter[cpu], vdd_dig, 0);
if (rc) {
pr_err("%s: vdd_dig (cpu%d) increase failed (%d)\n",
__func__, cpu, rc);
return rc;
}
/* Update per-core Scorpion voltage. */
rc = regulator_set_voltage(regulator_sc[cpu], vdd_sc, MAX_VDD_SC);
if (rc) {
pr_err("%s: vdd_sc (cpu%d) increase failed (%d)\n",
__func__, cpu, rc);
return rc;
}
return rc;
}
/* Apply any per-cpu voltage decreases. */
static void decrease_vdd(int cpu, unsigned int vdd_sc, unsigned int vdd_mem,
unsigned int vdd_dig)
{
int ret;
/* Update per-core Scorpion voltage. */
ret = regulator_set_voltage(regulator_sc[cpu], vdd_sc, MAX_VDD_SC);
if (ret) {
pr_err("%s: vdd_sc (cpu%d) decrease failed (%d)\n",
__func__, cpu, ret);
return;
}
/* Decrease vdd_dig active-set vote. */
ret = rpm_vreg_set_voltage(RPM_VREG_ID_PM8058_S1,
rpm_vreg_voter[cpu], vdd_dig, 0);
if (ret) {
pr_err("%s: vdd_dig (cpu%d) decrease failed (%d)\n",
__func__, cpu, ret);
return;
}
/* Decrease vdd_mem active-set after vdd_dig and vdd_sc.
* vdd_mem should be >= both vdd_sc and vdd_dig. */
ret = rpm_vreg_set_voltage(RPM_VREG_ID_PM8058_S0,
rpm_vreg_voter[cpu], vdd_mem, 0);
if (ret) {
pr_err("%s: vdd_mem (cpu%d) decrease failed (%d)\n",
__func__, cpu, ret);
return;
}
}
static void switch_sc_speed(int cpu, struct clkctl_acpu_speed *tgt_s)
{
struct clkctl_acpu_speed *strt_s = drv_state.current_speed[cpu];
if (strt_s->pll != ACPU_SCPLL && tgt_s->pll != ACPU_SCPLL) {
select_clk_source_div(cpu, tgt_s);
/* Select core source because target may be AFAB. */
select_core_source(cpu, tgt_s->core_src_sel);
} else if (strt_s->pll != ACPU_SCPLL && tgt_s->pll == ACPU_SCPLL) {
scpll_enable(cpu, tgt_s->l_val);
dsb();
select_core_source(cpu, tgt_s->core_src_sel);
} else if (strt_s->pll == ACPU_SCPLL && tgt_s->pll != ACPU_SCPLL) {
select_clk_source_div(cpu, tgt_s);
select_core_source(cpu, tgt_s->core_src_sel);
dsb();
scpll_disable(cpu);
} else
scpll_change_freq(cpu, tgt_s->l_val);
/* Update the driver state with the new clock freq */
drv_state.current_speed[cpu] = tgt_s;
}
int acpuclk_set_rate(int cpu, unsigned long rate, enum setrate_reason reason)
{
struct clkctl_acpu_speed *tgt_s, *strt_s;
struct clkctl_l2_speed *tgt_l2;
unsigned int vdd_mem, vdd_dig, pll_vdd_dig;
unsigned long flags;
int rc = 0;
if (cpu > num_possible_cpus()) {
rc = -EINVAL;
goto out;
}
if (reason == SETRATE_CPUFREQ) {
mutex_lock(&drv_state.lock);
#ifdef CONFIG_ACPUCLK_SET_RATE_DEBUG
set_rate_process = current;
mod_timer(&set_rate_timer, jiffies + SETRATE_TIMEOUT);
#endif
}
strt_s = drv_state.current_speed[cpu];
/* Return early if rate didn't change. */
if (rate == strt_s->acpuclk_khz)
goto out;
/* Find target frequency. */
for (tgt_s = acpu_freq_tbl; tgt_s->acpuclk_khz != 0; tgt_s++)
if (tgt_s->acpuclk_khz == rate)
break;
if (tgt_s->acpuclk_khz == 0) {
rc = -EINVAL;
goto out;
}
/* AVS needs SAW_VCTL to be intitialized correctly, before enable,
* and is not initialized at acpuclk_init().
*/
if (reason == SETRATE_CPUFREQ)
AVS_DISABLE(cpu);
/* Calculate vdd_mem and vdd_dig requirements.
* vdd_mem must be >= vdd_sc */
vdd_mem = max(tgt_s->vdd_sc, tgt_s->l2_level->vdd_mem);
/* Factor-in PLL vdd_dig requirements. */
if ((tgt_s->l2_level->khz > SCPLL_LOW_VDD_FMAX) ||
(tgt_s->pll == ACPU_SCPLL
&& tgt_s->acpuclk_khz > SCPLL_LOW_VDD_FMAX))
pll_vdd_dig = SCPLL_NOMINAL_VDD;
else
pll_vdd_dig = SCPLL_LOW_VDD;
vdd_dig = max(tgt_s->l2_level->vdd_dig, pll_vdd_dig);
/* Increase VDD levels if needed. */
if ((reason == SETRATE_CPUFREQ || reason == SETRATE_INIT)
&& (tgt_s->acpuclk_khz > strt_s->acpuclk_khz)) {
rc = increase_vdd(cpu, tgt_s->vdd_sc, vdd_mem, vdd_dig);
if (rc)
goto out;
}
dprintk("Switching from ACPU%d rate %u KHz -> %u KHz\n",
cpu, strt_s->acpuclk_khz, tgt_s->acpuclk_khz);
/* Switch CPU speed. */
switch_sc_speed(cpu, tgt_s);
/* Update the L2 vote and apply the rate change. */
spin_lock_irqsave(&drv_state.l2_lock, flags);
tgt_l2 = compute_l2_speed(cpu, tgt_s->l2_level);
set_l2_speed(tgt_l2);
spin_unlock_irqrestore(&drv_state.l2_lock, flags);
/* Nothing else to do for SWFI. */
if (reason == SETRATE_SWFI)
goto out;
/* Nothing else to do for power collapse. */
if (reason == SETRATE_PC)
goto out;
/* Update bus bandwith request. */
set_bus_bw(tgt_l2->bw_level);
/* Drop VDD levels if we can. */
if (tgt_s->acpuclk_khz < strt_s->acpuclk_khz)
decrease_vdd(cpu, tgt_s->vdd_sc, vdd_mem, vdd_dig);
dprintk("ACPU%d speed change complete\n", cpu);
/* Re-enable AVS */
if (reason == SETRATE_CPUFREQ)
AVS_ENABLE(cpu, tgt_s->avsdscr_setting);
out:
if (reason == SETRATE_CPUFREQ) {
mutex_unlock(&drv_state.lock);
#ifdef CONFIG_ACPUCLK_SET_RATE_DEBUG
del_timer(&set_rate_timer);
#endif
}
return rc;
}
static void __init scpll_init(int sc_pll)
{
uint32_t regval;
dprintk("Initializing SCPLL%d\n", sc_pll);
/* Clear calibration LUT registers containing max frequency entry.
* LUT registers are only writeable in debug mode. */
writel(SCPLL_DEBUG_FULL, sc_pll_base[sc_pll] + SCPLL_DEBUG_OFFSET);
writel(0x0, sc_pll_base[sc_pll] + SCPLL_LUT_A_HW_MAX);
writel(SCPLL_DEBUG_NONE, sc_pll_base[sc_pll] + SCPLL_DEBUG_OFFSET);
/* Power-up SCPLL into standby mode. */
writel(SCPLL_STANDBY, sc_pll_base[sc_pll] + SCPLL_CTL_OFFSET);
dsb();
udelay(10);
/* Calibrate the SCPLL to the maximum range supported by the h/w. We
* might not use the full range of calibrated frequencies, but this
* simplifies changes required for future increases in max CPU freq.
*/
regval = (L_VAL_SCPLL_CAL_MAX << 24) | (L_VAL_SCPLL_CAL_MIN << 16);
writel(regval, sc_pll_base[sc_pll] + SCPLL_CAL_OFFSET);
/* Start calibration */
writel(SCPLL_FULL_CAL, sc_pll_base[sc_pll] + SCPLL_CTL_OFFSET);
/* Wait for proof that calibration has started before checking the
* 'calibration done' bit in the status register. Waiting for the
* LUT register we cleared to contain data accomplishes this.
* This is required since the 'calibration done' bit takes time to
* transition from 'done' to 'not done' when starting a calibration.
*/
while (readl(sc_pll_base[sc_pll] + SCPLL_LUT_A_HW_MAX) == 0)
cpu_relax();
/* Wait for calibration to complete. */
while (readl(sc_pll_base[sc_pll] + SCPLL_STATUS_OFFSET) & 0x2)
cpu_relax();
/* Power-down SCPLL. */
scpll_disable(sc_pll);
}
/* Force ACPU core and L2 cache clocks to rates that don't require SCPLLs. */
static void __init unselect_scplls(void)
{
int cpu;
/* Ensure CAL_IDX frequency uses AFAB sources for CPU cores and L2. */
BUG_ON(acpu_freq_tbl[CAL_IDX].core_src_sel != 0);
BUG_ON(acpu_freq_tbl[CAL_IDX].l2_level->src_sel != 0);
for_each_possible_cpu(cpu) {
select_clk_source_div(cpu, &acpu_freq_tbl[CAL_IDX]);
select_core_source(cpu, acpu_freq_tbl[CAL_IDX].core_src_sel);
drv_state.current_speed[cpu] = &acpu_freq_tbl[CAL_IDX];
l2_vote[cpu] = acpu_freq_tbl[CAL_IDX].l2_level;
}
select_core_source(L2, acpu_freq_tbl[CAL_IDX].l2_level->src_sel);
drv_state.current_l2_speed = acpu_freq_tbl[CAL_IDX].l2_level;
}
/* Ensure SCPLLs use the 27MHz PXO. */
static void __init scpll_set_refs(void)
{
int cpu;
uint32_t regval;
/* Bit 4 = 0:PXO, 1:MXO. */
for_each_possible_cpu(cpu) {
regval = readl(sc_pll_base[cpu] + SCPLL_CFG_OFFSET);
regval &= ~BIT(4);
writel(regval, sc_pll_base[cpu] + SCPLL_CFG_OFFSET);
}
regval = readl(sc_pll_base[L2] + SCPLL_CFG_OFFSET);
regval &= ~BIT(4);
writel(regval, sc_pll_base[L2] + SCPLL_CFG_OFFSET);
}
/* Voltage regulator initialization. */
static void __init regulator_init(void)
{
struct clkctl_acpu_speed **freq = drv_state.current_speed;
const char *regulator_sc_name[] = {"8901_s0", "8901_s1"};
int cpu, ret;
for_each_possible_cpu(cpu) {
/* VDD_SC0, VDD_SC1 */
regulator_sc[cpu] = regulator_get(NULL, regulator_sc_name[cpu]);
if (IS_ERR(regulator_sc[cpu]))
goto err;
ret = regulator_set_voltage(regulator_sc[cpu],
freq[cpu]->vdd_sc, MAX_VDD_SC);
if (ret)
goto err;
ret = regulator_enable(regulator_sc[cpu]);
if (ret)
goto err;
}
return;
err:
pr_err("%s: Failed to initialize voltage regulators\n", __func__);
BUG();
}
/* Register with bus driver. */
static void __init bus_init(void)
{
bus_perf_client = msm_bus_scale_register_client(&bus_client_pdata);
if (!bus_perf_client) {
pr_err("%s: unable register bus client\n", __func__);
BUG();
}
}
#ifdef CONFIG_CPU_FREQ_MSM
static struct cpufreq_frequency_table freq_table[NR_CPUS][20];
static void __init cpufreq_table_init(void)
{
int cpu;
for_each_possible_cpu(cpu) {
int i, freq_cnt = 0;
/* Construct the freq_table tables from acpu_freq_tbl. */
for (i = 0; acpu_freq_tbl[i].acpuclk_khz != 0
&& freq_cnt < ARRAY_SIZE(*freq_table); i++) {
if (acpu_freq_tbl[i].use_for_scaling[cpu]) {
freq_table[cpu][freq_cnt].index = freq_cnt;
freq_table[cpu][freq_cnt].frequency
= acpu_freq_tbl[i].acpuclk_khz;
freq_cnt++;
}
}
/* freq_table not big enough to store all usable freqs. */
BUG_ON(acpu_freq_tbl[i].acpuclk_khz != 0);
freq_table[cpu][freq_cnt].index = freq_cnt;
freq_table[cpu][freq_cnt].frequency = CPUFREQ_TABLE_END;
pr_info("CPU%d: %d scaling frequencies supported.\n",
cpu, freq_cnt);
/* Register table with CPUFreq. */
cpufreq_frequency_table_get_attr(freq_table[cpu], cpu);
}
}
#else
static void __init cpufreq_table_init(void) {}
#endif
static unsigned int __init select_freq_plan(void)
{
uint32_t raw_speed_bin, speed_bin, max_khz;
struct clkctl_acpu_speed *f;
acpu_freq_tbl = acpu_freq_tbl_v2;
l2_freq_tbl = l2_freq_tbl_v2;
l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_v2);
raw_speed_bin = readl(QFPROM_SPEED_BIN_ADDR);
speed_bin = raw_speed_bin & 0xF;
if (speed_bin == 0xF)
speed_bin = (raw_speed_bin >> 4) & 0xF;
if (speed_bin == 0x1)
max_khz = 1512000;
else
max_khz = 1188000;
/* Truncate the table based to max_khz. */
for (f = acpu_freq_tbl; f->acpuclk_khz != 0; f++) {
if (f->acpuclk_khz > max_khz) {
f->acpuclk_khz = 0;
break;
}
}
f--;
pr_info("Max ACPU freq: %u KHz\n", f->acpuclk_khz);
return f->acpuclk_khz;
}
void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata)
{
unsigned int max_cpu_khz;
int cpu;
mutex_init(&drv_state.lock);
spin_lock_init(&drv_state.l2_lock);
drv_state.acpu_switch_time_us = clkdata->acpu_switch_time_us;
drv_state.vdd_switch_time_us = clkdata->vdd_switch_time_us;
/* Configure hardware. */
max_cpu_khz = select_freq_plan();
unselect_scplls();
scpll_set_refs();
for_each_possible_cpu(cpu)
scpll_init(cpu);
scpll_init(L2);
regulator_init();
bus_init();
/* Improve boot time by ramping up CPUs immediately. */
for_each_online_cpu(cpu)
acpuclk_set_rate(cpu, max_cpu_khz, SETRATE_INIT);
cpufreq_table_init();
}
Realize that this is my first modification so there might be some mistakes...
I would recommend you scroll up slowly from the bottom and look for the if/else statement that still limits you to 1.2
Also, check your math on max voltages available to the clock speed at 1.5 - I know it'll work, but you are a bit undervolted for proper operation. Not too big a deal, but might lead to losing information from RAM if left unchecked and not changed elsewhere. (unless you are shooting for an undervolt kernel - but then you'd have to re-scale the rest of the voltages down the line)
Don't forget to crawl through the rest of the kernel code on the hardware side and make sure there aren't any other limiters preventing your change from taking place - board-doubleshot.c is another place you will find 1.2 limiters enacted combined with voltage regulation.
I am hesitant to lay out a how-to on this, because it's very easy to melt your chip if not careful, or fry the RAM or GPU if you don't do your math right for voltage regulation across the mainboard. Also because teaching math is something i'm not very good at and get frustrated easily trying to do.
Explaining how to do math for processor scaling is way beyond my abilities for providing here, so google becomes your friend and a lot of math workshops are in your near future if you want to get into doing this.
I would also spend some time reading up on dual-core theory and the principles behind preventing both cores from trying to steal each others work.
Since the info is sitting right here for anyone who wants to download kernel source and give it a shot, just please, make sure you know what you are doing when you start messing with voltages or you will break your phone on a hardware level. Melting your processor or frying your RAM is no fun.
Releasing an overclock kernel to the community that has not been thoroughly tested without very clearly stating so is negligent, so please, please make sure you aren't frying people's phones before pushing ahead with something like this publicly. (general statement for anyone reading this)
I am glad to see other people getting into this, cautionary words aside, and look forward to what people come up with.