提交 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 @@
struct clk;
extern struct cpufreq_frequency_table sw64_clockmod_table[];
extern char curruent_policy[CPUFREQ_NAME_LEN];
struct clk_ops {
......@@ -44,7 +42,7 @@ struct clk {
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);
......
// SPDX-License-Identifier: GPL-2.0
/*
* linux/arch/sw/kernel/setup.c
*
* Copyright (C) 1995 Linus Torvalds
*/
#include <linux/clk.h>
#include <linux/cpufreq.h>
......@@ -11,6 +6,7 @@
#include <linux/export.h>
#include <linux/delay.h>
#include <asm/sw64_init.h>
#include <asm/sw64io.h>
#include <asm/hw_init.h>
#include <asm/debug.h>
......@@ -29,73 +25,7 @@
#define CORE_PLL0_CFG_SHIFT 4
#define CORE_PLL2_CFG_SHIFT 18
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);
char curruent_policy[CPUFREQ_NAME_LEN];
static struct clk cpu_clk = {
.name = "cpu_clk",
......@@ -113,13 +43,13 @@ unsigned int __sw64_cpufreq_get(struct cpufreq_policy *policy)
{
int i;
u64 val;
struct cpufreq_frequency_table *ft = policy->freq_table;
val = sw64_io_read(0, CLK_CTL);
val = val >> CORE_PLL2_CFG_SHIFT;
val = sw64_io_read(0, CLK_CTL) >> CORE_PLL2_CFG_SHIFT;
for (i = 0; i < sizeof(cpu_freq)/sizeof(int); i++) {
if (cpu_freq[val] == cpu_freq[i])
return cpu_freq[i];
for (i = 0; ft[i].frequency != CPUFREQ_TABLE_END; i++) {
if (val == ft[i].driver_data)
return ft[i].frequency;
}
return 0;
}
......@@ -131,61 +61,41 @@ void sw64_store_policy(struct cpufreq_policy *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;
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++) {
if (rate == cpu_freq[i]) {
index = i;
update_cpu_freq(cpu_freq[i]);
break;
}
}
if (index < 0)
return;
for (i = 0; i < cpu_num; i++) {
sw64_io_write(i, CLK_CTL, CORE_CLK2_R | CORE_CLK2_V | CLK_PRT);
val = sw64_io_read(i, CLK_CTL);
sw64_io_write(0, CLK_CTL, CORE_CLK2_R | CORE_CLK2_V | CLK_PRT);
sw64_io_write(1, CLK_CTL, CORE_CLK2_R | CORE_CLK2_V | CLK_PRT);
val = sw64_io_read(0, CLK_CTL);
sw64_io_write(i, CLK_CTL, val | index << CORE_PLL2_CFG_SHIFT);
sw64_io_write(0, CLK_CTL, val | index << CORE_PLL2_CFG_SHIFT);
sw64_io_write(1, CLK_CTL, val | index << CORE_PLL2_CFG_SHIFT);
udelay(1);
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
| index << CORE_PLL2_CFG_SHIFT);
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 */
sw64_io_write(i, CLU_LV1_SEL, CLK_LV1_SEL_MUXA | CLK_LV1_SEL_PRT);
/* LV1 select PLL1/PLL2 */
sw64_io_write(0, CLU_LV1_SEL, CLK_LV1_SEL_MUXA | CLK_LV1_SEL_PRT);
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);
/* Set CLK_CTL PLL0 */
sw64_io_write(0, CLK_CTL, val | CORE_CLK0_R | CORE_CLK0_V);
sw64_io_write(1, CLK_CTL, val | CORE_CLK0_R | CORE_CLK0_V);
sw64_io_write(i, CLK_CTL, val | CORE_CLK0_R | CORE_CLK0_V
| index << CORE_PLL0_CFG_SHIFT);
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
| index << CORE_PLL0_CFG_SHIFT);
udelay(1);
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
| index << CORE_PLL0_CFG_SHIFT);
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);
/* LV1 select PLL0/PLL1 */
sw64_io_write(i, CLU_LV1_SEL, CLK_LV1_SEL_MUXB | CLK_LV1_SEL_PRT);
}
}
EXPORT_SYMBOL_GPL(sw64_set_rate);
......@@ -21,11 +21,40 @@
#include <asm/hw_init.h>
#include <asm/clock.h>
#include <asm/sw64io.h>
#define CRYSTAL_BIT (1UL << 34)
static uint nowait;
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,
unsigned long val, void *data);
......@@ -37,12 +66,10 @@ static int sw64_cpu_freq_notifier(struct notifier_block *nb,
unsigned long val, void *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)
sw64_update_clockevents(cpu, freqs->new * 1000);
}
if (val == CPUFREQ_POSTCHANGE)
sw64_update_clockevents(cpu, freqs->new * 1000000);
return 0;
}
......@@ -57,7 +84,7 @@ static unsigned int sw64_cpufreq_get(unsigned int cpu)
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)
static int sw64_cpufreq_target(struct cpufreq_policy *policy,
unsigned int index)
{
unsigned long freq;
unsigned int cpu = policy->cpu;
freq = 50000 * index;
if (!cpu_online(cpu))
return -ENODEV;
sw64_store_policy(policy);
/* setting the cpu frequency */
sw64_set_rate(freq * 1000);
sw64_set_rate(index);
return 0;
}
static int sw64_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
unsigned long rate;
int i;
unsigned long max_rate, freq_off;
cpuclk = sw64_clk_get(NULL, "cpu_clk");
if (IS_ERR(cpuclk)) {
......@@ -89,27 +117,36 @@ static int sw64_cpufreq_cpu_init(struct cpufreq_policy *policy)
return PTR_ERR(cpuclk);
}
rate = get_cpu_freq() / 1000;
max_rate = get_cpu_freq() / 1000000;
/* clock table init */
for (i = 0;
(sw64_clockmod_table[i].frequency != CPUFREQ_TABLE_END);
i++)
if (sw64_clockmod_table[i].frequency == 0)
sw64_clockmod_table[i].frequency = (rate * i) / 48;
if (sw64_io_read(0, INIT_CTL) & CRYSTAL_BIT)
freq_off = 50;
else
freq_off = 60;
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;
cpufreq_generic_init(policy, &sw64_clockmod_table[0], 0);
cpufreq_generic_init(policy, freq_table, 0);
return 0;
}
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)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册