185 lines
4.9 KiB
C
185 lines
4.9 KiB
C
// 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>
|
|
#include <linux/errno.h>
|
|
#include <linux/export.h>
|
|
#include <linux/delay.h>
|
|
|
|
#include <asm/sw64io.h>
|
|
#include <asm/hw_init.h>
|
|
#include <asm/debug.h>
|
|
#include <asm/clock.h>
|
|
|
|
#define CLK_PRT 0x1UL
|
|
#define CORE_CLK0_V (0x1UL << 1)
|
|
#define CORE_CLK0_R (0x1UL << 2)
|
|
#define CORE_CLK2_V (0x1UL << 15)
|
|
#define CORE_CLK2_R (0x1UL << 16)
|
|
|
|
#define CLK_LV1_SEL_PRT 0x1UL
|
|
#define CLK_LV1_SEL_MUXA (0x1UL << 2)
|
|
#define CLK_LV1_SEL_MUXB (0x1UL << 3)
|
|
|
|
#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);
|
|
|
|
static struct clk cpu_clk = {
|
|
.name = "cpu_clk",
|
|
.flags = CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES,
|
|
.rate = 2400000000,
|
|
};
|
|
|
|
struct clk *sw64_clk_get(struct device *dev, const char *id)
|
|
{
|
|
return &cpu_clk;
|
|
}
|
|
EXPORT_SYMBOL(sw64_clk_get);
|
|
|
|
unsigned long sw64_clk_get_rate(struct clk *clk)
|
|
{
|
|
if (!clk)
|
|
return 0;
|
|
|
|
return (unsigned long)clk->rate;
|
|
}
|
|
EXPORT_SYMBOL(sw64_clk_get_rate);
|
|
|
|
void sw64_store_policy(struct cpufreq_policy *policy)
|
|
{
|
|
memcpy(curruent_policy, policy->governor->name, CPUFREQ_NAME_LEN);
|
|
}
|
|
EXPORT_SYMBOL_GPL(sw64_store_policy);
|
|
|
|
int sw64_set_rate(int index, unsigned long rate)
|
|
{
|
|
unsigned int i, val;
|
|
|
|
rate /= 1000000;
|
|
|
|
for (i = 0; i < sizeof(cpu_freq)/sizeof(int); i++) {
|
|
if (rate == cpu_freq[i]) {
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (index < 0)
|
|
return -EINVAL;
|
|
|
|
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(0, CLK_CTL, val | index << CORE_PLL2_CFG_SHIFT);
|
|
sw64_io_write(1, 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
|
|
| index << CORE_PLL2_CFG_SHIFT);
|
|
val = sw64_io_read(0, 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);
|
|
|
|
/* 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(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);
|
|
|
|
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);
|
|
|
|
return index;
|
|
}
|
|
EXPORT_SYMBOL_GPL(sw64_set_rate);
|