Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 177895
b: refs/heads/master
c: f8ede0f
h: refs/heads/master
i:
  177893: 44c9f75
  177891: f04f373
  177887: 0ae5570
v: v3
  • Loading branch information
Wu Zhangjin authored and Ralf Baechle committed Dec 17, 2009
1 parent 44b80b3 commit 43f8299
Show file tree
Hide file tree
Showing 14 changed files with 525 additions and 5 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 9726b43a4d7aaa5b30f559e78768aeb3d17bc224
refs/heads/master: f8ede0f700f5478851f242f291d203cde54ca6cf
64 changes: 64 additions & 0 deletions trunk/arch/mips/include/asm/clock.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#ifndef __ASM_MIPS_CLOCK_H
#define __ASM_MIPS_CLOCK_H

#include <linux/kref.h>
#include <linux/list.h>
#include <linux/seq_file.h>
#include <linux/clk.h>

extern void (*cpu_wait) (void);

struct clk;

struct clk_ops {
void (*init) (struct clk *clk);
void (*enable) (struct clk *clk);
void (*disable) (struct clk *clk);
void (*recalc) (struct clk *clk);
int (*set_rate) (struct clk *clk, unsigned long rate, int algo_id);
long (*round_rate) (struct clk *clk, unsigned long rate);
};

struct clk {
struct list_head node;
const char *name;
int id;
struct module *owner;

struct clk *parent;
struct clk_ops *ops;

struct kref kref;

unsigned long rate;
unsigned long flags;
};

#define CLK_ALWAYS_ENABLED (1 << 0)
#define CLK_RATE_PROPAGATES (1 << 1)

/* Should be defined by processor-specific code */
void arch_init_clk_ops(struct clk_ops **, int type);

int clk_init(void);

int __clk_enable(struct clk *);
void __clk_disable(struct clk *);

void clk_recalc_rate(struct clk *);

int clk_register(struct clk *);
void clk_unregister(struct clk *);

/* the exported API, in addition to clk_set_rate */
/**
* clk_set_rate_ex - set the clock rate for a clock source, with additional parameter
* @clk: clock source
* @rate: desired clock rate in Hz
* @algo_id: algorithm id to be passed down to ops->set_rate
*
* Returns success (0) or negative errno.
*/
int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id);

#endif /* __ASM_MIPS_CLOCK_H */
2 changes: 2 additions & 0 deletions trunk/arch/mips/include/asm/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@
#define PRID_REV_VR4181A 0x0070 /* Same as VR4122 */
#define PRID_REV_VR4130 0x0080
#define PRID_REV_34K_V1_0_2 0x0022
#define PRID_REV_LOONGSON2E 0x0002
#define PRID_REV_LOONGSON2F 0x0003

/*
* Older processors used to encode processor version and revision in two
Expand Down
6 changes: 5 additions & 1 deletion trunk/arch/mips/include/asm/mach-loongson/loongson.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,12 @@ extern void mach_irq_dispatch(unsigned int pending);
#define LOONGSON_PCIMAP_WIN(WIN, ADDR) \
((((ADDR)>>26) & LOONGSON_PCIMAP_PCIMAP_LO0) << ((WIN)*6))

/* Chip Config */
#ifdef CONFIG_CPU_SUPPORTS_CPUFREQ
#include <linux/cpufreq.h>
extern void loongson2_cpu_wait(void);
extern struct cpufreq_frequency_table loongson2_clockmod_table[];

/* Chip Config */
#define LOONGSON_CHIPCFG0 LOONGSON_REG(LOONGSON_REGBASE + 0x80)
#endif

Expand Down
2 changes: 2 additions & 0 deletions trunk/arch/mips/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,6 @@ CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/n

obj-$(CONFIG_HAVE_STD_PC_SERIAL_PORT) += 8250-platform.o

obj-$(CONFIG_MIPS_CPUFREQ) += cpufreq/

EXTRA_CFLAGS += -Werror
2 changes: 2 additions & 0 deletions trunk/arch/mips/kernel/cpu-probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <linux/ptrace.h>
#include <linux/smp.h>
#include <linux/stddef.h>
#include <linux/module.h>

#include <asm/bugs.h>
#include <asm/cpu.h>
Expand All @@ -32,6 +33,7 @@
* the CPU very much.
*/
void (*cpu_wait)(void);
EXPORT_SYMBOL(cpu_wait);

static void r3081_wait(void)
{
Expand Down
14 changes: 14 additions & 0 deletions trunk/arch/mips/kernel/cpufreq/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,20 @@ if CPU_FREQ

comment "CPUFreq processor drivers"

config LOONGSON2_CPUFREQ
tristate "Loongson2 CPUFreq Driver"
select CPU_FREQ_TABLE
depends on MIPS_CPUFREQ
help
This option adds a CPUFreq driver for loongson processors which
support software configurable cpu frequency.

Loongson2F and it's successors support this feature.

For details, take a look at <file:Documentation/cpu-freq/>.

If in doubt, say N.

endif # CPU_FREQ

endmenu
Expand Down
5 changes: 5 additions & 0 deletions trunk/arch/mips/kernel/cpufreq/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#
# Makefile for the Linux/MIPS cpufreq.
#

obj-$(CONFIG_LOONGSON2_CPUFREQ) += loongson2_cpufreq.o loongson2_clock.o
166 changes: 166 additions & 0 deletions trunk/arch/mips/kernel/cpufreq/loongson2_clock.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/*
* Copyright (C) 2006 - 2008 Lemote Inc. & Insititute of Computing Technology
* Author: Yanhua, yanh@lemote.com
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/

#include <linux/cpufreq.h>
#include <linux/platform_device.h>

#include <asm/clock.h>

#include <loongson.h>

static LIST_HEAD(clock_list);
static DEFINE_SPINLOCK(clock_lock);
static DEFINE_MUTEX(clock_list_sem);

/* Minimum CLK support */
enum {
DC_ZERO, DC_25PT = 2, DC_37PT, DC_50PT, DC_62PT, DC_75PT,
DC_87PT, DC_DISABLE, DC_RESV
};

struct cpufreq_frequency_table loongson2_clockmod_table[] = {
{DC_RESV, CPUFREQ_ENTRY_INVALID},
{DC_ZERO, CPUFREQ_ENTRY_INVALID},
{DC_25PT, 0},
{DC_37PT, 0},
{DC_50PT, 0},
{DC_62PT, 0},
{DC_75PT, 0},
{DC_87PT, 0},
{DC_DISABLE, 0},
{DC_RESV, CPUFREQ_TABLE_END},
};
EXPORT_SYMBOL_GPL(loongson2_clockmod_table);

static struct clk cpu_clk = {
.name = "cpu_clk",
.flags = CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES,
.rate = 800000000,
};

struct clk *clk_get(struct device *dev, const char *id)
{
return &cpu_clk;
}
EXPORT_SYMBOL(clk_get);

static void propagate_rate(struct clk *clk)
{
struct clk *clkp;

list_for_each_entry(clkp, &clock_list, node) {
if (likely(clkp->parent != clk))
continue;
if (likely(clkp->ops && clkp->ops->recalc))
clkp->ops->recalc(clkp);
if (unlikely(clkp->flags & CLK_RATE_PROPAGATES))
propagate_rate(clkp);
}
}

int clk_enable(struct clk *clk)
{
return 0;
}
EXPORT_SYMBOL(clk_enable);

void clk_disable(struct clk *clk)
{
}
EXPORT_SYMBOL(clk_disable);

unsigned long clk_get_rate(struct clk *clk)
{
return (unsigned long)clk->rate;
}
EXPORT_SYMBOL(clk_get_rate);

void clk_put(struct clk *clk)
{
}
EXPORT_SYMBOL(clk_put);

int clk_set_rate(struct clk *clk, unsigned long rate)
{
return clk_set_rate_ex(clk, rate, 0);
}
EXPORT_SYMBOL_GPL(clk_set_rate);

int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id)
{
int ret = 0;
int regval;
int i;

if (likely(clk->ops && clk->ops->set_rate)) {
unsigned long flags;

spin_lock_irqsave(&clock_lock, flags);
ret = clk->ops->set_rate(clk, rate, algo_id);
spin_unlock_irqrestore(&clock_lock, flags);
}

if (unlikely(clk->flags & CLK_RATE_PROPAGATES))
propagate_rate(clk);

for (i = 0; loongson2_clockmod_table[i].frequency != CPUFREQ_TABLE_END;
i++) {
if (loongson2_clockmod_table[i].frequency ==
CPUFREQ_ENTRY_INVALID)
continue;
if (rate == loongson2_clockmod_table[i].frequency)
break;
}
if (rate != loongson2_clockmod_table[i].frequency)
return -ENOTSUPP;

clk->rate = rate;

regval = LOONGSON_CHIPCFG0;
regval = (regval & ~0x7) | (loongson2_clockmod_table[i].index - 1);
LOONGSON_CHIPCFG0 = regval;

return ret;
}
EXPORT_SYMBOL_GPL(clk_set_rate_ex);

long clk_round_rate(struct clk *clk, unsigned long rate)
{
if (likely(clk->ops && clk->ops->round_rate)) {
unsigned long flags, rounded;

spin_lock_irqsave(&clock_lock, flags);
rounded = clk->ops->round_rate(clk, rate);
spin_unlock_irqrestore(&clock_lock, flags);

return rounded;
}

return rate;
}
EXPORT_SYMBOL_GPL(clk_round_rate);

/*
* This is the simple version of Loongson-2 wait, Maybe we need do this in
* interrupt disabled content
*/

DEFINE_SPINLOCK(loongson2_wait_lock);
void loongson2_cpu_wait(void)
{
u32 cpu_freq;
unsigned long flags;

spin_lock_irqsave(&loongson2_wait_lock, flags);
cpu_freq = LOONGSON_CHIPCFG0;
LOONGSON_CHIPCFG0 &= ~0x7; /* Put CPU into wait mode */
LOONGSON_CHIPCFG0 = cpu_freq; /* Restore CPU state */
spin_unlock_irqrestore(&loongson2_wait_lock, flags);
}
EXPORT_SYMBOL_GPL(loongson2_cpu_wait);
Loading

0 comments on commit 43f8299

Please sign in to comment.