提交 f015f9a2 编写于 作者: T Tang Jinyang 提交者: guzitao

sw64: add DVFS support for different boards

Sunway inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I56QDM

--------------------------------

This patch add two supports:
    * Initialize frequency table according to frequency of external
      crystal.
    * Set the initial frequency as the higest one to avoid exceeding
      the limit on some boards.
Signed-off-by: NTang Jinyang <tangjinyang@wxiat.com>
Reviewed-by: NHe Sheng <hesheng@wxiat.com>
Signed-off-by: NGu Zitao <guzitao@wxiat.com>
上级 3860d52f
...@@ -11,8 +11,6 @@ ...@@ -11,8 +11,6 @@
struct clk; struct clk;
extern struct cpufreq_frequency_table sw64_clockmod_table[];
extern char curruent_policy[CPUFREQ_NAME_LEN]; extern char curruent_policy[CPUFREQ_NAME_LEN];
struct clk_ops { struct clk_ops {
...@@ -44,7 +42,7 @@ struct clk { ...@@ -44,7 +42,7 @@ struct clk {
int clk_init(void); int clk_init(void);
void sw64_set_rate(unsigned long rate); void sw64_set_rate(unsigned int index);
struct clk *sw64_clk_get(struct device *dev, const char *id); struct clk *sw64_clk_get(struct device *dev, const char *id);
......
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/*
* linux/arch/sw/kernel/setup.c
*
* Copyright (C) 1995 Linus Torvalds
*/
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
...@@ -11,6 +6,7 @@ ...@@ -11,6 +6,7 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <asm/sw64_init.h>
#include <asm/sw64io.h> #include <asm/sw64io.h>
#include <asm/hw_init.h> #include <asm/hw_init.h>
#include <asm/debug.h> #include <asm/debug.h>
...@@ -29,73 +25,7 @@ ...@@ -29,73 +25,7 @@
#define CORE_PLL0_CFG_SHIFT 4 #define CORE_PLL0_CFG_SHIFT 4
#define CORE_PLL2_CFG_SHIFT 18 #define CORE_PLL2_CFG_SHIFT 18
char curruent_policy[CPUFREQ_NAME_LEN]; char curruent_policy[CPUFREQ_NAME_LEN];
/* Minimum CLK support */
enum {
DC_0, DC_1, DC_2, DC_3, DC_4, DC_5, DC_6, DC_7, DC_8,
DC_9, DC_10, DC_11, DC_12, DC_13, DC_14, DC_15, DC_16, DC_RESV
};
static int cpu_freq[14] = {
0, 1200, 1800, 1900,
1950, 2000, 2050, 2100,
2150, 2200, 2250, 2300,
2350, 2400 };
struct cpufreq_frequency_table sw64_clockmod_table[] = {
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{0, DC_1, 0},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{0, DC_2, 0},
{-1, DC_RESV, CPUFREQ_ENTRY_INVALID},
{0, DC_3, 0},
{0, DC_4, 0},
{0, DC_5, 0},
{0, DC_6, 0},
{0, DC_7, 0},
{0, DC_8, 0},
{0, DC_9, 0},
{0, DC_10, 0},
{0, DC_11, 0},
{0, DC_12, 0},
{0, DC_13, 0},
{-1, DC_RESV, CPUFREQ_TABLE_END},
};
EXPORT_SYMBOL_GPL(sw64_clockmod_table);
static struct clk cpu_clk = { static struct clk cpu_clk = {
.name = "cpu_clk", .name = "cpu_clk",
...@@ -113,13 +43,13 @@ unsigned int __sw64_cpufreq_get(struct cpufreq_policy *policy) ...@@ -113,13 +43,13 @@ unsigned int __sw64_cpufreq_get(struct cpufreq_policy *policy)
{ {
int i; int i;
u64 val; u64 val;
struct cpufreq_frequency_table *ft = policy->freq_table;
val = sw64_io_read(0, CLK_CTL); val = sw64_io_read(0, CLK_CTL) >> CORE_PLL2_CFG_SHIFT;
val = val >> CORE_PLL2_CFG_SHIFT;
for (i = 0; i < sizeof(cpu_freq)/sizeof(int); i++) { for (i = 0; ft[i].frequency != CPUFREQ_TABLE_END; i++) {
if (cpu_freq[val] == cpu_freq[i]) if (val == ft[i].driver_data)
return cpu_freq[i]; return ft[i].frequency;
} }
return 0; return 0;
} }
...@@ -131,61 +61,41 @@ void sw64_store_policy(struct cpufreq_policy *policy) ...@@ -131,61 +61,41 @@ void sw64_store_policy(struct cpufreq_policy *policy)
} }
EXPORT_SYMBOL_GPL(sw64_store_policy); EXPORT_SYMBOL_GPL(sw64_store_policy);
void sw64_set_rate(unsigned long rate) void sw64_set_rate(unsigned int index)
{ {
unsigned int i, val; unsigned int i, val;
int index = -1; int cpu_num;
rate /= 1000000; cpu_num = sw64_chip->get_cpu_num();
for (i = 0; i < sizeof(cpu_freq)/sizeof(int); i++) { for (i = 0; i < cpu_num; i++) {
if (rate == cpu_freq[i]) { sw64_io_write(i, CLK_CTL, CORE_CLK2_R | CORE_CLK2_V | CLK_PRT);
index = i; val = sw64_io_read(i, CLK_CTL);
update_cpu_freq(cpu_freq[i]);
break;
}
}
if (index < 0)
return;
sw64_io_write(0, CLK_CTL, CORE_CLK2_R | CORE_CLK2_V | CLK_PRT); sw64_io_write(i, CLK_CTL, val | index << CORE_PLL2_CFG_SHIFT);
sw64_io_write(1, CLK_CTL, CORE_CLK2_R | CORE_CLK2_V | CLK_PRT);
val = sw64_io_read(0, CLK_CTL);
sw64_io_write(0, CLK_CTL, val | index << CORE_PLL2_CFG_SHIFT); udelay(1);
sw64_io_write(1, CLK_CTL, val | index << CORE_PLL2_CFG_SHIFT);
udelay(1); sw64_io_write(i, CLK_CTL, CORE_CLK2_V | CLK_PRT
| index << CORE_PLL2_CFG_SHIFT);
val = sw64_io_read(i, CLK_CTL);
sw64_io_write(0, CLK_CTL, CORE_CLK2_V | CLK_PRT /* LV1 select PLL1/PLL2 */
| index << CORE_PLL2_CFG_SHIFT); sw64_io_write(i, CLU_LV1_SEL, CLK_LV1_SEL_MUXA | CLK_LV1_SEL_PRT);
sw64_io_write(1, CLK_CTL, CORE_CLK2_V | CLK_PRT
| index << CORE_PLL2_CFG_SHIFT);
val = sw64_io_read(0, CLK_CTL);
/* LV1 select PLL1/PLL2 */ /* Set CLK_CTL PLL0 */
sw64_io_write(0, CLU_LV1_SEL, CLK_LV1_SEL_MUXA | CLK_LV1_SEL_PRT); sw64_io_write(i, CLK_CTL, val | CORE_CLK0_R | CORE_CLK0_V);
sw64_io_write(1, CLU_LV1_SEL, CLK_LV1_SEL_MUXA | CLK_LV1_SEL_PRT);
/* Set CLK_CTL PLL0 */ sw64_io_write(i, CLK_CTL, val | CORE_CLK0_R | CORE_CLK0_V
sw64_io_write(0, CLK_CTL, val | CORE_CLK0_R | CORE_CLK0_V); | index << CORE_PLL0_CFG_SHIFT);
sw64_io_write(1, CLK_CTL, val | CORE_CLK0_R | CORE_CLK0_V);
sw64_io_write(0, CLK_CTL, val | CORE_CLK0_R | CORE_CLK0_V udelay(1);
| index << CORE_PLL0_CFG_SHIFT);
sw64_io_write(1, CLK_CTL, val | CORE_CLK0_R | CORE_CLK0_V
| index << CORE_PLL0_CFG_SHIFT);
udelay(1); sw64_io_write(i, CLK_CTL, val | CORE_CLK0_V
| index << CORE_PLL0_CFG_SHIFT);
sw64_io_write(0, CLK_CTL, val | CORE_CLK0_V /* LV1 select PLL0/PLL1 */
| index << CORE_PLL0_CFG_SHIFT); sw64_io_write(i, CLU_LV1_SEL, CLK_LV1_SEL_MUXB | CLK_LV1_SEL_PRT);
sw64_io_write(1, CLK_CTL, val | CORE_CLK0_V }
| index << CORE_PLL0_CFG_SHIFT);
/* LV1 select PLL0/PLL1 */
sw64_io_write(0, CLU_LV1_SEL, CLK_LV1_SEL_MUXB | CLK_LV1_SEL_PRT);
sw64_io_write(1, CLU_LV1_SEL, CLK_LV1_SEL_MUXB | CLK_LV1_SEL_PRT);
} }
EXPORT_SYMBOL_GPL(sw64_set_rate); EXPORT_SYMBOL_GPL(sw64_set_rate);
...@@ -21,11 +21,40 @@ ...@@ -21,11 +21,40 @@
#include <asm/hw_init.h> #include <asm/hw_init.h>
#include <asm/clock.h> #include <asm/clock.h>
#include <asm/sw64io.h>
#define CRYSTAL_BIT (1UL << 34)
static uint nowait; static uint nowait;
static struct clk *cpuclk; static struct clk *cpuclk;
/* Minimum CLK support */
enum {
DC_0, DC_1, DC_2, DC_3, DC_4, DC_5, DC_6, DC_7, DC_8,
DC_9, DC_10, DC_11, DC_12, DC_13, DC_14, DC_15, DC_RESV
};
static struct cpufreq_frequency_table freq_table[] = {
{0, DC_0, CPUFREQ_ENTRY_INVALID},
{0, DC_1, 0},
{0, DC_2, 0},
{0, DC_3, 0},
{0, DC_4, 0},
{0, DC_5, 0},
{0, DC_6, 0},
{0, DC_7, 0},
{0, DC_8, 0},
{0, DC_9, 0},
{0, DC_10, 0},
{0, DC_11, 0},
{0, DC_12, 0},
{0, DC_13, 0},
{0, DC_14, 0},
{0, DC_15, 0},
{-1, DC_RESV, CPUFREQ_TABLE_END},
};
static int sw64_cpu_freq_notifier(struct notifier_block *nb, static int sw64_cpu_freq_notifier(struct notifier_block *nb,
unsigned long val, void *data); unsigned long val, void *data);
...@@ -37,12 +66,10 @@ static int sw64_cpu_freq_notifier(struct notifier_block *nb, ...@@ -37,12 +66,10 @@ static int sw64_cpu_freq_notifier(struct notifier_block *nb,
unsigned long val, void *data) unsigned long val, void *data)
{ {
struct cpufreq_freqs *freqs = (struct cpufreq_freqs *)data; struct cpufreq_freqs *freqs = (struct cpufreq_freqs *)data;
unsigned long cpu; unsigned long cpu = freqs->policy->cpu;
for_each_online_cpu(cpu) { if (val == CPUFREQ_POSTCHANGE)
if (val == CPUFREQ_POSTCHANGE) sw64_update_clockevents(cpu, freqs->new * 1000000);
sw64_update_clockevents(cpu, freqs->new * 1000);
}
return 0; return 0;
} }
...@@ -57,7 +84,7 @@ static unsigned int sw64_cpufreq_get(unsigned int cpu) ...@@ -57,7 +84,7 @@ static unsigned int sw64_cpufreq_get(unsigned int cpu)
return 0; return 0;
} }
return __sw64_cpufreq_get(policy) * 1000; return __sw64_cpufreq_get(policy);
} }
/* /*
...@@ -66,22 +93,23 @@ static unsigned int sw64_cpufreq_get(unsigned int cpu) ...@@ -66,22 +93,23 @@ static unsigned int sw64_cpufreq_get(unsigned int cpu)
static int sw64_cpufreq_target(struct cpufreq_policy *policy, static int sw64_cpufreq_target(struct cpufreq_policy *policy,
unsigned int index) unsigned int index)
{ {
unsigned long freq; unsigned int cpu = policy->cpu;
freq = 50000 * index; if (!cpu_online(cpu))
return -ENODEV;
sw64_store_policy(policy); sw64_store_policy(policy);
/* setting the cpu frequency */ /* setting the cpu frequency */
sw64_set_rate(freq * 1000); sw64_set_rate(index);
return 0; return 0;
} }
static int sw64_cpufreq_cpu_init(struct cpufreq_policy *policy) static int sw64_cpufreq_cpu_init(struct cpufreq_policy *policy)
{ {
unsigned long rate;
int i; int i;
unsigned long max_rate, freq_off;
cpuclk = sw64_clk_get(NULL, "cpu_clk"); cpuclk = sw64_clk_get(NULL, "cpu_clk");
if (IS_ERR(cpuclk)) { if (IS_ERR(cpuclk)) {
...@@ -89,27 +117,36 @@ static int sw64_cpufreq_cpu_init(struct cpufreq_policy *policy) ...@@ -89,27 +117,36 @@ static int sw64_cpufreq_cpu_init(struct cpufreq_policy *policy)
return PTR_ERR(cpuclk); return PTR_ERR(cpuclk);
} }
rate = get_cpu_freq() / 1000; max_rate = get_cpu_freq() / 1000000;
/* clock table init */ if (sw64_io_read(0, INIT_CTL) & CRYSTAL_BIT)
for (i = 0; freq_off = 50;
(sw64_clockmod_table[i].frequency != CPUFREQ_TABLE_END); else
i++) freq_off = 60;
if (sw64_clockmod_table[i].frequency == 0)
sw64_clockmod_table[i].frequency = (rate * i) / 48;
sw64_set_rate(rate * 1000); /* clock table init */
for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
if (i == 1)
freq_table[i].frequency = freq_off * 24;
if (i == 2)
freq_table[i].frequency = freq_off * 36;
if (i > 2)
freq_table[i].frequency = freq_off * 38 + ((i - 3) * freq_off);
if (freq_table[i].frequency == max_rate)
freq_table[i + 1].frequency = CPUFREQ_TABLE_END;
}
policy->clk = cpuclk; policy->clk = cpuclk;
cpufreq_generic_init(policy, &sw64_clockmod_table[0], 0); cpufreq_generic_init(policy, freq_table, 0);
return 0; return 0;
} }
static int sw64_cpufreq_verify(struct cpufreq_policy_data *policy) static int sw64_cpufreq_verify(struct cpufreq_policy_data *policy)
{ {
return cpufreq_frequency_table_verify(policy, &sw64_clockmod_table[0]); return cpufreq_frequency_table_verify(policy, freq_table);
} }
static int sw64_cpufreq_exit(struct cpufreq_policy *policy) static int sw64_cpufreq_exit(struct cpufreq_policy *policy)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册