Commit f015f9a2 authored by Tang Jinyang's avatar Tang Jinyang Committed by guzitao
Browse files

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: default avatarTang Jinyang <tangjinyang@wxiat.com>
Reviewed-by: default avatarHe Sheng <hesheng@wxiat.com>
Signed-off-by: default avatarGu Zitao <guzitao@wxiat.com>
parent 3860d52f
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -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);

+30 −120
Original line number Diff line number Diff line
// 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>
@@ -31,72 +27,6 @@

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 = {
	.name = "cpu_clk",
	.flags = CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES,
@@ -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;

	rate /= 1000000;

	for (i = 0; i < sizeof(cpu_freq)/sizeof(int); i++) {
		if (rate == cpu_freq[i]) {
			index = i;
			update_cpu_freq(cpu_freq[i]);
			break;
		}
	}
	int cpu_num;

	if (index < 0)
		return;
	cpu_num = sw64_chip->get_cpu_num();

	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);
	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, val | index << CORE_PLL2_CFG_SHIFT);
	sw64_io_write(1, CLK_CTL, val | index << CORE_PLL2_CFG_SHIFT);
		sw64_io_write(i, CLK_CTL, val | index << CORE_PLL2_CFG_SHIFT);

		udelay(1);

	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
		sw64_io_write(i, CLK_CTL, CORE_CLK2_V | CLK_PRT
				| index << CORE_PLL2_CFG_SHIFT);
	val = sw64_io_read(0, CLK_CTL);
		val = sw64_io_read(i, CLK_CTL);

		/* 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);
		sw64_io_write(i, CLU_LV1_SEL, CLK_LV1_SEL_MUXA | CLK_LV1_SEL_PRT);

		/* 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);

	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(i, CLK_CTL, val | CORE_CLK0_R | CORE_CLK0_V
				| index << CORE_PLL0_CFG_SHIFT);

		udelay(1);

	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
		sw64_io_write(i, 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);
		sw64_io_write(i, CLU_LV1_SEL, CLK_LV1_SEL_MUXB | CLK_LV1_SEL_PRT);
	}
}
EXPORT_SYMBOL_GPL(sw64_set_rate);
+57 −20
Original line number Diff line number Diff line
@@ -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);
	}
		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)