* [PATCH v1 0/3] Add CPUFreq support for loongson2f
@ 2009-11-16 17:32 Wu Zhangjin
[not found] ` <cover.1258392631.git.wuzhangjin@gmail.com>
0 siblings, 1 reply; 7+ messages in thread
From: Wu Zhangjin @ 2009-11-16 17:32 UTC (permalink / raw)
To: Ralf Baechle
Cc: linux-mips, cpufreq, Dave Jones, Dominik Brodowski, yanh, huhb,
Wu Zhangjin
This patchset adds CPUFreq support for loongson2f, 'Cause loongson2f doesn't
have a fixed MIPS Timer(relative to cpu frequency), If we enable CPUFreq, the
system time will be broken. So, an external Timer is needed, Herein, In Lemote
loongson2f family machine, there is a CS5536 MFGPT Timer, in Dexxon Gdium, it
use i8253.
This v1 revision have incorporated with the feedbacks from "Dominik Brodowski"
and Ralf. And this Thread have replied more feedbacks from Ralf:
http://www.linux-mips.org/archives/linux-mips/2009-11/msg00292.html
Best Regards,
Wu Zhangjin
Wu Zhangjin (3):
[loongson] lemote-2f: add cs5536 MFGPT timer support
MIPS: add basic options for CPUFreq support
[loongson] 2f: add CPUFreq support
arch/mips/Kconfig | 3 +
arch/mips/include/asm/clock.h | 64 ++++++
.../asm/mach-loongson/cs5536/cs5536_mfgpt.h | 35 +++
arch/mips/include/asm/mach-loongson/loongson.h | 6 +-
arch/mips/kernel/Makefile | 2 +
arch/mips/kernel/cpu-probe.c | 2 +
arch/mips/kernel/cpufreq/Kconfig | 41 ++++
arch/mips/kernel/cpufreq/Makefile | 5 +
arch/mips/kernel/cpufreq/loongson2_clock.c | 166 +++++++++++++++
arch/mips/kernel/cpufreq/loongson2_cpufreq.c | 202 ++++++++++++++++++
arch/mips/loongson/Kconfig | 16 ++-
arch/mips/loongson/common/cs5536/Makefile | 5 +
arch/mips/loongson/common/cs5536/cs5536_mfgpt.c | 217 ++++++++++++++++++++
arch/mips/loongson/common/env.c | 3 +
arch/mips/loongson/common/time.c | 3 +
15 files changed, 767 insertions(+), 3 deletions(-)
create mode 100644 arch/mips/include/asm/clock.h
create mode 100644 arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h
create mode 100644 arch/mips/kernel/cpufreq/Kconfig
create mode 100644 arch/mips/kernel/cpufreq/Makefile
create mode 100644 arch/mips/kernel/cpufreq/loongson2_clock.c
create mode 100644 arch/mips/kernel/cpufreq/loongson2_cpufreq.c
create mode 100644 arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v1 1/3] [loongson] lemote-2f: add cs5536 MFGPT timer support
[not found] ` <cover.1258392631.git.wuzhangjin@gmail.com>
@ 2009-11-16 17:32 ` Wu Zhangjin
2009-11-17 13:10 ` Ralf Baechle
2009-11-16 17:32 ` [PATCH v1 2/3] MIPS: add basic options for CPUFreq support Wu Zhangjin
2009-11-16 17:32 ` [PATCH v1 3/3] [loongson] 2f: add " Wu Zhangjin
2 siblings, 1 reply; 7+ messages in thread
From: Wu Zhangjin @ 2009-11-16 17:32 UTC (permalink / raw)
To: Ralf Baechle
Cc: linux-mips, cpufreq, Dave Jones, Dominik Brodowski, yanh, huhb,
Wu Zhangjin
When we want to enable CPUFreq support for loongson2f, it need an
external timer, this patch add it.
'Cause the frequency of the MIPS Timer is half of the cpu frequency, if
we use it with Cpufreq support, the sytem time will become not accuracy.
And we export the mfgpt0 counter disable/enable operations for the
coming suspend support to suspend/resume the timer.
Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
---
.../asm/mach-loongson/cs5536/cs5536_mfgpt.h | 35 +++
arch/mips/loongson/Kconfig | 11 +
arch/mips/loongson/common/cs5536/Makefile | 5 +
arch/mips/loongson/common/cs5536/cs5536_mfgpt.c | 217 ++++++++++++++++++++
arch/mips/loongson/common/time.c | 3 +
5 files changed, 271 insertions(+), 0 deletions(-)
create mode 100644 arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h
create mode 100644 arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
diff --git a/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h
new file mode 100644
index 0000000..4b493d6
--- /dev/null
+++ b/arch/mips/include/asm/mach-loongson/cs5536/cs5536_mfgpt.h
@@ -0,0 +1,35 @@
+/*
+ * cs5536 mfgpt header file
+ */
+
+#ifndef _CS5536_MFGPT_H
+#define _CS5536_MFGPT_H
+
+#include <cs5536/cs5536.h>
+#include <cs5536/cs5536_pci.h>
+
+#ifdef CONFIG_CS5536_MFGPT
+extern void setup_mfgpt0_timer(void);
+extern void disable_mfgpt0_counter(void);
+extern void enable_mfgpt0_counter(void);
+#else
+static inline void __maybe_unused setup_mfgpt0_timer(void)
+{
+}
+static inline void __maybe_unused disable_mfgpt0_counter(void)
+{
+}
+static inline void __maybe_unused enable_mfgpt0_counter(void)
+{
+}
+#endif
+
+#define MFGPT_TICK_RATE 14318000
+#define COMPARE ((MFGPT_TICK_RATE + HZ/2) / HZ)
+
+#define MFGPT_BASE mfgpt_base
+#define MFGPT0_CMP2 (MFGPT_BASE + 2)
+#define MFGPT0_CNT (MFGPT_BASE + 4)
+#define MFGPT0_SETUP (MFGPT_BASE + 6)
+
+#endif /*!_CS5536_MFGPT_H */
diff --git a/arch/mips/loongson/Kconfig b/arch/mips/loongson/Kconfig
index 17e72fd..8b5cc13 100644
--- a/arch/mips/loongson/Kconfig
+++ b/arch/mips/loongson/Kconfig
@@ -62,6 +62,17 @@ endchoice
config CS5536
bool
+config CS5536_MFGPT
+ bool "CS5536 MFGPT Timer"
+ depends on CS5536
+ help
+ This option enables the mfgpt0 timer of AMD CS5536.
+
+ If you want to enable the Loongson2 CPUFreq Driver, Please enable
+ this option at first, otherwise, You will get wrong system time.
+
+ If unsure, say Yes.
+
config LOONGSON_SUSPEND
bool
default y
diff --git a/arch/mips/loongson/common/cs5536/Makefile b/arch/mips/loongson/common/cs5536/Makefile
index 31657ee..510d4cd 100644
--- a/arch/mips/loongson/common/cs5536/Makefile
+++ b/arch/mips/loongson/common/cs5536/Makefile
@@ -5,4 +5,9 @@
obj-$(CONFIG_CS5536) += cs5536_pci.o cs5536_ide.o cs5536_acc.o cs5536_ohci.o \
cs5536_isa.o cs5536_ehci.o
+#
+# Enable cs5536 mfgpt Timer
+#
+obj-$(CONFIG_CS5536_MFGPT) += cs5536_mfgpt.o
+
EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c b/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
new file mode 100644
index 0000000..6cb44db
--- /dev/null
+++ b/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
@@ -0,0 +1,217 @@
+/*
+ * CS5536 General timer functions
+ *
+ * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology
+ * Author: Yanhua, yanh@lemote.com
+ *
+ * Copyright (C) 2009 Lemote Inc.
+ * Author: Wu zhangjin, wuzj@lemote.com
+ *
+ * Reference: AMD Geode(TM) CS5536 Companion Device Data Book
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/clockchips.h>
+
+#include <asm/time.h>
+
+#include <cs5536/cs5536_mfgpt.h>
+
+DEFINE_SPINLOCK(mfgpt_lock);
+EXPORT_SYMBOL(mfgpt_lock);
+
+static u32 mfgpt_base;
+
+/*
+ * Initialize the MFGPT timer.
+ *
+ * This is also called after resume to bring the MFGPT into operation again.
+ */
+
+/* disable counter */
+void disable_mfgpt0_counter(void)
+{
+ outw(inw(MFGPT0_SETUP) & 0x7fff, MFGPT0_SETUP);
+}
+EXPORT_SYMBOL(disable_mfgpt0_counter);
+
+/* enable counter, comparator2 to event mode, 14.318MHz clock */
+void enable_mfgpt0_counter(void)
+{
+ outw(0xe310, MFGPT0_SETUP);
+}
+EXPORT_SYMBOL(enable_mfgpt0_counter);
+
+static void init_mfgpt_timer(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ spin_lock(&mfgpt_lock);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ outw(COMPARE, MFGPT0_CMP2); /* set comparator2 */
+ outw(0, MFGPT0_CNT); /* set counter to 0 */
+ enable_mfgpt0_counter();
+ break;
+
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_UNUSED:
+ if (evt->mode == CLOCK_EVT_MODE_PERIODIC ||
+ evt->mode == CLOCK_EVT_MODE_ONESHOT)
+ disable_mfgpt0_counter();
+ break;
+
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* The oneshot mode have very high deviation, Not use it! */
+ break;
+
+ case CLOCK_EVT_MODE_RESUME:
+ /* Nothing to do here */
+ break;
+ }
+ spin_unlock(&mfgpt_lock);
+}
+
+static struct clock_event_device mfgpt_clockevent = {
+ .name = "mfgpt",
+ .features = CLOCK_EVT_FEAT_PERIODIC,
+ .set_mode = init_mfgpt_timer,
+ .irq = CS5536_MFGPT_INTR,
+};
+
+static irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+ u32 basehi;
+
+ /*
+ * get MFGPT base address
+ *
+ * NOTE: do not remove me, it's need for the value of mfgpt_base is
+ * variable
+ */
+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base);
+
+ /* ack */
+ outw(inw(MFGPT0_SETUP) | 0x4000, MFGPT0_SETUP);
+
+ mfgpt_clockevent.event_handler(&mfgpt_clockevent);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction irq5 = {
+ .handler = timer_interrupt,
+ .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER,
+ .name = "timer"
+};
+
+/*
+ * Initialize the conversion factor and the min/max deltas of the clock event
+ * structure and register the clock event source with the framework.
+ */
+void __init setup_mfgpt0_timer(void)
+{
+ u32 basehi;
+ struct clock_event_device *cd = &mfgpt_clockevent;
+ unsigned int cpu = smp_processor_id();
+
+ cd->cpumask = cpumask_of(cpu);
+ clockevent_set_clock(cd, MFGPT_TICK_RATE);
+ cd->max_delta_ns = clockevent_delta2ns(0xffff, cd);
+ cd->min_delta_ns = clockevent_delta2ns(0xf, cd);
+
+ /* Enable MFGPT0 Comparator 2 Output to the Interrupt Mapper */
+ _wrmsr(DIVIL_MSR_REG(MFGPT_IRQ), 0, 0x100);
+
+ /* Enable Interrupt Gate 5 */
+ _wrmsr(DIVIL_MSR_REG(PIC_ZSEL_LOW), 0, 0x50000);
+
+ /* get MFGPT base address */
+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base);
+
+ clockevents_register_device(cd);
+
+ setup_irq(CS5536_MFGPT_INTR, &irq5);
+}
+
+/*
+ * Since the MFGPT overflows every tick, its not very useful
+ * to just read by itself. So use jiffies to emulate a free
+ * running counter:
+ */
+static cycle_t mfgpt_read(struct clocksource *cs)
+{
+ unsigned long flags;
+ int count;
+ u32 jifs;
+ static int old_count;
+ static u32 old_jifs;
+
+ spin_lock_irqsave(&mfgpt_lock, flags);
+ /*
+ * Although our caller may have the read side of xtime_lock,
+ * this is now a seqlock, and we are cheating in this routine
+ * by having side effects on state that we cannot undo if
+ * there is a collision on the seqlock and our caller has to
+ * retry. (Namely, old_jifs and old_count.) So we must treat
+ * jiffies as volatile despite the lock. We read jiffies
+ * before latching the timer count to guarantee that although
+ * the jiffies value might be older than the count (that is,
+ * the counter may underflow between the last point where
+ * jiffies was incremented and the point where we latch the
+ * count), it cannot be newer.
+ */
+ jifs = jiffies;
+ /* read the count */
+ count = inw(MFGPT0_CNT);
+
+ /*
+ * It's possible for count to appear to go the wrong way for this
+ * reason:
+ *
+ * The timer counter underflows, but we haven't handled the resulting
+ * interrupt and incremented jiffies yet.
+ *
+ * Previous attempts to handle these cases intelligently were buggy, so
+ * we just do the simple thing now.
+ */
+ if (count < old_count && jifs == old_jifs)
+ count = old_count;
+
+ old_count = count;
+ old_jifs = jifs;
+
+ spin_unlock_irqrestore(&mfgpt_lock, flags);
+
+ return (cycle_t) (jifs * COMPARE) + count;
+}
+
+static struct clocksource clocksource_mfgpt = {
+ .name = "mfgpt",
+ .rating = 120, /* Functional for real use, but not desired */
+ .read = mfgpt_read,
+ .mask = CLOCKSOURCE_MASK(32),
+ .mult = 0,
+ .shift = 22,
+};
+
+int __init init_mfgpt_clocksource(void)
+{
+ if (num_possible_cpus() > 1) /* MFGPT does not scale! */
+ return 0;
+
+ clocksource_mfgpt.mult = clocksource_hz2mult(MFGPT_TICK_RATE, 22);
+ return clocksource_register(&clocksource_mfgpt);
+}
+
+arch_initcall(init_mfgpt_clocksource);
diff --git a/arch/mips/loongson/common/time.c b/arch/mips/loongson/common/time.c
index 6e08c82..35f0b66 100644
--- a/arch/mips/loongson/common/time.c
+++ b/arch/mips/loongson/common/time.c
@@ -14,11 +14,14 @@
#include <asm/time.h>
#include <loongson.h>
+#include <cs5536/cs5536_mfgpt.h>
void __init plat_time_init(void)
{
/* setup mips r4k timer */
mips_hpt_frequency = cpu_clock_freq / 2;
+
+ setup_mfgpt0_timer();
}
void read_persistent_clock(struct timespec *ts)
--
1.6.2.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v1 2/3] MIPS: add basic options for CPUFreq support
[not found] ` <cover.1258392631.git.wuzhangjin@gmail.com>
2009-11-16 17:32 ` [PATCH v1 1/3] [loongson] lemote-2f: add cs5536 MFGPT timer support Wu Zhangjin
@ 2009-11-16 17:32 ` Wu Zhangjin
2009-11-17 13:10 ` Ralf Baechle
2009-11-16 17:32 ` [PATCH v1 3/3] [loongson] 2f: add " Wu Zhangjin
2 siblings, 1 reply; 7+ messages in thread
From: Wu Zhangjin @ 2009-11-16 17:32 UTC (permalink / raw)
To: Ralf Baechle
Cc: linux-mips, cpufreq, Dave Jones, Dominik Brodowski, yanh, huhb,
Wu Zhangjin
This patch adds basic options for MIPS CPUFreq support.
Since MIPS Timer's frequency is relative to the processor's frequency,
So, MIPS CPUFreq support not only need the processor's CPUFreq support
but also need an external timer. otherwise, we will make the system time
"mussy".
Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
---
arch/mips/Kconfig | 3 +++
arch/mips/kernel/cpufreq/Kconfig | 27 +++++++++++++++++++++++++++
2 files changed, 30 insertions(+), 0 deletions(-)
create mode 100644 arch/mips/kernel/cpufreq/Kconfig
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 0e4b510..bfe8c39 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -2146,6 +2146,7 @@ config MMU
config I8253
bool
+ select MIPS_EXTERNAL_TIMER
config ZONE_DMA32
bool
@@ -2222,6 +2223,8 @@ source "kernel/power/Kconfig"
endmenu
+source "arch/mips/kernel/cpufreq/Kconfig"
+
source "net/Kconfig"
source "drivers/Kconfig"
diff --git a/arch/mips/kernel/cpufreq/Kconfig b/arch/mips/kernel/cpufreq/Kconfig
new file mode 100644
index 0000000..37983a1
--- /dev/null
+++ b/arch/mips/kernel/cpufreq/Kconfig
@@ -0,0 +1,27 @@
+#
+# CPU Frequency scaling
+#
+
+config MIPS_EXTERNAL_TIMER
+ bool
+
+config MIPS_CPUFREQ
+ bool
+ default y
+ depends on CPU_SUPPORTS_CPUFREQ && MIPS_EXTERNAL_TIMER
+
+if MIPS_CPUFREQ
+
+menu "CPU Frequency scaling"
+
+source "drivers/cpufreq/Kconfig"
+
+if CPU_FREQ
+
+comment "CPUFreq processor drivers"
+
+endif # CPU_FREQ
+
+endmenu
+
+endif # MIPS_CPUFREQ
--
1.6.2.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v1 3/3] [loongson] 2f: add CPUFreq support
[not found] ` <cover.1258392631.git.wuzhangjin@gmail.com>
2009-11-16 17:32 ` [PATCH v1 1/3] [loongson] lemote-2f: add cs5536 MFGPT timer support Wu Zhangjin
2009-11-16 17:32 ` [PATCH v1 2/3] MIPS: add basic options for CPUFreq support Wu Zhangjin
@ 2009-11-16 17:32 ` Wu Zhangjin
2009-11-17 13:10 ` Ralf Baechle
2 siblings, 1 reply; 7+ messages in thread
From: Wu Zhangjin @ 2009-11-16 17:32 UTC (permalink / raw)
To: Ralf Baechle
Cc: linux-mips, cpufreq, Dave Jones, Dominik Brodowski, yanh, huhb,
Wu Zhangjin
Loongson2f add a new capability to dynamicly scale cpu frequency. And
when we put it into wait mode via setting the frequency as ZERO, it will
wait there until an external interrupt take place, which will help
saving power for us.
And as the last patch described, to enable this support, an external
timer is needed to avoid getting wrong system time when using the MIPS
Timer, 'Cause the MIPS Timer's frequency is half of the cpu frequency,
when the cpu frequency is changed, the MIPS Timer will be not accuracy.
This version incorporates the feedback from "Dominik Brodowski
<linux@dominikbrodowski.net>" to register transition notifier before
register_driver().
Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
---
arch/mips/include/asm/clock.h | 64 ++++++++
arch/mips/include/asm/mach-loongson/loongson.h | 6 +-
arch/mips/kernel/Makefile | 2 +
arch/mips/kernel/cpu-probe.c | 2 +
arch/mips/kernel/cpufreq/Kconfig | 14 ++
arch/mips/kernel/cpufreq/Makefile | 5 +
arch/mips/kernel/cpufreq/loongson2_clock.c | 166 +++++++++++++++++++
arch/mips/kernel/cpufreq/loongson2_cpufreq.c | 202 ++++++++++++++++++++++++
arch/mips/loongson/Kconfig | 5 +-
arch/mips/loongson/common/env.c | 3 +
10 files changed, 466 insertions(+), 3 deletions(-)
create mode 100644 arch/mips/include/asm/clock.h
create mode 100644 arch/mips/kernel/cpufreq/Makefile
create mode 100644 arch/mips/kernel/cpufreq/loongson2_clock.c
create mode 100644 arch/mips/kernel/cpufreq/loongson2_cpufreq.c
diff --git a/arch/mips/include/asm/clock.h b/arch/mips/include/asm/clock.h
new file mode 100644
index 0000000..83894aa
--- /dev/null
+++ b/arch/mips/include/asm/clock.h
@@ -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 */
diff --git a/arch/mips/include/asm/mach-loongson/loongson.h b/arch/mips/include/asm/mach-loongson/loongson.h
index 9ee40df..daf7041 100644
--- a/arch/mips/include/asm/mach-loongson/loongson.h
+++ b/arch/mips/include/asm/mach-loongson/loongson.h
@@ -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
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index e953c6d..6a9adff 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -91,6 +91,8 @@ 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
CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS)
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 7a51866..80e202e 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -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>
@@ -32,6 +33,7 @@
* the CPU very much.
*/
void (*cpu_wait)(void);
+EXPORT_SYMBOL(cpu_wait);
static void r3081_wait(void)
{
diff --git a/arch/mips/kernel/cpufreq/Kconfig b/arch/mips/kernel/cpufreq/Kconfig
index 37983a1..58c601e 100644
--- a/arch/mips/kernel/cpufreq/Kconfig
+++ b/arch/mips/kernel/cpufreq/Kconfig
@@ -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
diff --git a/arch/mips/kernel/cpufreq/Makefile b/arch/mips/kernel/cpufreq/Makefile
new file mode 100644
index 0000000..c3479a4
--- /dev/null
+++ b/arch/mips/kernel/cpufreq/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Linux/MIPS cpufreq.
+#
+
+obj-$(CONFIG_LOONGSON2_CPUFREQ) += loongson2_cpufreq.o loongson2_clock.o
diff --git a/arch/mips/kernel/cpufreq/loongson2_clock.c b/arch/mips/kernel/cpufreq/loongson2_clock.c
new file mode 100644
index 0000000..d7ca256
--- /dev/null
+++ b/arch/mips/kernel/cpufreq/loongson2_clock.c
@@ -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);
diff --git a/arch/mips/kernel/cpufreq/loongson2_cpufreq.c b/arch/mips/kernel/cpufreq/loongson2_cpufreq.c
new file mode 100644
index 0000000..7232dcb
--- /dev/null
+++ b/arch/mips/kernel/cpufreq/loongson2_cpufreq.c
@@ -0,0 +1,202 @@
+/*
+ * Cpufreq driver for the loongson-2 processors
+ *
+ * The 2E revision of loongson processor not support this feature.
+ *
+ * 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/module.h>
+#include <linux/err.h>
+#include <linux/sched.h> /* set_cpus_allowed() */
+#include <linux/delay.h>
+
+#include <asm/clock.h>
+
+#include <loongson.h>
+
+static uint nowait;
+
+static struct clk *cpuclk;
+
+static void (*saved_cpu_wait) (void);
+
+static int loongson2_cpu_freq_notifier(struct notifier_block *nb,
+ unsigned long val, void *data);
+
+static struct notifier_block loongson2_cpufreq_notifier_block = {
+ .notifier_call = loongson2_cpu_freq_notifier
+};
+
+static int loongson2_cpu_freq_notifier(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ if (val == CPUFREQ_POSTCHANGE)
+ current_cpu_data.udelay_val = loops_per_jiffy;
+
+ return 0;
+}
+
+static unsigned int loongson2_cpufreq_get(unsigned int cpu)
+{
+ return clk_get_rate(cpuclk);
+}
+
+/*
+ * Here we notify other drivers of the proposed change and the final change.
+ */
+static int loongson2_cpufreq_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ unsigned int cpu = policy->cpu;
+ unsigned int newstate = 0;
+ cpumask_t cpus_allowed;
+ struct cpufreq_freqs freqs;
+ unsigned int freq;
+
+ if (!cpu_online(cpu))
+ return -ENODEV;
+
+ cpus_allowed = current->cpus_allowed;
+ set_cpus_allowed(current, cpumask_of_cpu(cpu));
+
+ if (cpufreq_frequency_table_target
+ (policy, &loongson2_clockmod_table[0], target_freq, relation,
+ &newstate))
+ return -EINVAL;
+
+ freq =
+ ((cpu_clock_freq / 1000) *
+ loongson2_clockmod_table[newstate].index) / 8;
+ if (freq < policy->min || freq > policy->max)
+ return -EINVAL;
+
+ pr_debug("cpufreq: requested frequency %u Hz\n", target_freq * 1000);
+
+ freqs.cpu = cpu;
+ freqs.old = loongson2_cpufreq_get(cpu);
+ freqs.new = freq;
+ freqs.flags = 0;
+
+ if (freqs.new == freqs.old)
+ return 0;
+
+ /* notifiers */
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ set_cpus_allowed(current, cpus_allowed);
+
+ /* setting the cpu frequency */
+ clk_set_rate(cpuclk, freq);
+
+ /* notifiers */
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+ pr_debug("cpufreq: set frequency %u kHz\n", freq);
+
+ return 0;
+}
+
+static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+ int i;
+
+ if (!cpu_online(policy->cpu))
+ return -ENODEV;
+
+ cpuclk = clk_get(NULL, "cpu_clk");
+ if (IS_ERR(cpuclk)) {
+ printk(KERN_ERR "cpufreq: couldn't get CPU clk\n");
+ return PTR_ERR(cpuclk);
+ }
+
+ cpuclk->rate = cpu_clock_freq / 1000;
+ if (!cpuclk->rate)
+ return -EINVAL;
+
+ /* clock table init */
+ for (i = 2;
+ (loongson2_clockmod_table[i].frequency != CPUFREQ_TABLE_END);
+ i++)
+ loongson2_clockmod_table[i].frequency = (cpuclk->rate * i) / 8;
+
+ policy->cur = loongson2_cpufreq_get(policy->cpu);
+
+ cpufreq_frequency_table_get_attr(&loongson2_clockmod_table[0],
+ policy->cpu);
+
+ return cpufreq_frequency_table_cpuinfo(policy,
+ &loongson2_clockmod_table[0]);
+}
+
+static int loongson2_cpufreq_verify(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy,
+ &loongson2_clockmod_table[0]);
+}
+
+static int loongson2_cpufreq_exit(struct cpufreq_policy *policy)
+{
+ clk_put(cpuclk);
+ return 0;
+}
+
+static struct freq_attr *loongson2_table_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+static struct cpufreq_driver loongson2_cpufreq_driver = {
+ .owner = THIS_MODULE,
+ .name = "loongson2",
+ .init = loongson2_cpufreq_cpu_init,
+ .verify = loongson2_cpufreq_verify,
+ .target = loongson2_cpufreq_target,
+ .get = loongson2_cpufreq_get,
+ .exit = loongson2_cpufreq_exit,
+ .attr = loongson2_table_attr,
+};
+
+static int __init cpufreq_init(void)
+{
+ int result;
+
+ printk(KERN_INFO "cpufreq: Loongson-2F CPU frequency driver.\n");
+
+ cpufreq_register_notifier(&loongson2_cpufreq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+
+ result = cpufreq_register_driver(&loongson2_cpufreq_driver);
+
+ if (!result && !nowait) {
+ saved_cpu_wait = cpu_wait;
+ cpu_wait = loongson2_cpu_wait;
+ }
+
+ return result;
+}
+
+static void __exit cpufreq_exit(void)
+{
+ if (!nowait && saved_cpu_wait)
+ cpu_wait = saved_cpu_wait;
+ cpufreq_unregister_driver(&loongson2_cpufreq_driver);
+ cpufreq_unregister_notifier(&loongson2_cpufreq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+module_init(cpufreq_init);
+module_exit(cpufreq_exit);
+
+module_param(nowait, uint, 0644);
+MODULE_PARM_DESC(nowait, "Disable Loongson-2F specific wait");
+
+MODULE_AUTHOR("Yanhua <yanh@lemote.com>");
+MODULE_DESCRIPTION("cpufreq driver for Loongson2F");
+MODULE_LICENSE("GPL");
diff --git a/arch/mips/loongson/Kconfig b/arch/mips/loongson/Kconfig
index 8b5cc13..7a86987 100644
--- a/arch/mips/loongson/Kconfig
+++ b/arch/mips/loongson/Kconfig
@@ -34,10 +34,10 @@ config LEMOTE_MACH2F
select ARCH_SPARSEMEM_ENABLE
select BOARD_SCACHE
select BOOT_ELF32
- select CEVT_R4K
+ select CEVT_R4K if ! MIPS_EXTERNAL_TIMER
select CPU_HAS_WB
select CS5536
- select CSRC_R4K
+ select CSRC_R4K if ! MIPS_EXTERNAL_TIMER
select DMA_NONCOHERENT
select GENERIC_HARDIRQS_NO__DO_IRQ
select GENERIC_ISA_DMA_SUPPORT_BROKEN
@@ -65,6 +65,7 @@ config CS5536
config CS5536_MFGPT
bool "CS5536 MFGPT Timer"
depends on CS5536
+ select MIPS_EXTERNAL_TIMER
help
This option enables the mfgpt0 timer of AMD CS5536.
diff --git a/arch/mips/loongson/common/env.c b/arch/mips/loongson/common/env.c
index b9ef503..196d947 100644
--- a/arch/mips/loongson/common/env.c
+++ b/arch/mips/loongson/common/env.c
@@ -17,11 +17,14 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
+#include <linux/module.h>
+
#include <asm/bootinfo.h>
#include <loongson.h>
unsigned long bus_clock, cpu_clock_freq;
+EXPORT_SYMBOL(cpu_clock_freq);
unsigned long memsize, highmemsize;
/* pmon passes arguments in 32bit pointers */
--
1.6.2.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v1 1/3] [loongson] lemote-2f: add cs5536 MFGPT timer support
2009-11-16 17:32 ` [PATCH v1 1/3] [loongson] lemote-2f: add cs5536 MFGPT timer support Wu Zhangjin
@ 2009-11-17 13:10 ` Ralf Baechle
0 siblings, 0 replies; 7+ messages in thread
From: Ralf Baechle @ 2009-11-17 13:10 UTC (permalink / raw)
To: Wu Zhangjin
Cc: linux-mips, cpufreq, Dave Jones, Dominik Brodowski, yanh, huhb
On Tue, Nov 17, 2009 at 01:32:57AM +0800, Wu Zhangjin wrote:
> Subject: [PATCH v1 1/3] [loongson] lemote-2f: add cs5536 MFGPT timer support
>
> When we want to enable CPUFreq support for loongson2f, it need an
> external timer, this patch add it.
>
> 'Cause the frequency of the MIPS Timer is half of the cpu frequency, if
> we use it with Cpufreq support, the sytem time will become not accuracy.
>
> And we export the mfgpt0 counter disable/enable operations for the
> coming suspend support to suspend/resume the timer.
Thanks, queue for 2.6.33.
Ralf
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v1 2/3] MIPS: add basic options for CPUFreq support
2009-11-16 17:32 ` [PATCH v1 2/3] MIPS: add basic options for CPUFreq support Wu Zhangjin
@ 2009-11-17 13:10 ` Ralf Baechle
0 siblings, 0 replies; 7+ messages in thread
From: Ralf Baechle @ 2009-11-17 13:10 UTC (permalink / raw)
To: Wu Zhangjin
Cc: linux-mips, cpufreq, Dave Jones, Dominik Brodowski, yanh, huhb
On Tue, Nov 17, 2009 at 01:32:58AM +0800, Wu Zhangjin wrote:
> Subject: [PATCH v1 2/3] MIPS: add basic options for CPUFreq support
>
> This patch adds basic options for MIPS CPUFreq support.
>
> Since MIPS Timer's frequency is relative to the processor's frequency,
> So, MIPS CPUFreq support not only need the processor's CPUFreq support
> but also need an external timer. otherwise, we will make the system time
> "mussy".
Thanks, queue for 2.6.33.
Ralf
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v1 3/3] [loongson] 2f: add CPUFreq support
2009-11-16 17:32 ` [PATCH v1 3/3] [loongson] 2f: add " Wu Zhangjin
@ 2009-11-17 13:10 ` Ralf Baechle
0 siblings, 0 replies; 7+ messages in thread
From: Ralf Baechle @ 2009-11-17 13:10 UTC (permalink / raw)
To: Wu Zhangjin
Cc: linux-mips, cpufreq, Dave Jones, Dominik Brodowski, yanh, huhb
On Tue, Nov 17, 2009 at 01:32:59AM +0800, Wu Zhangjin wrote:
> Subject: [PATCH v1 3/3] [loongson] 2f: add CPUFreq support
>
> Loongson2f add a new capability to dynamicly scale cpu frequency. And
> when we put it into wait mode via setting the frequency as ZERO, it will
> wait there until an external interrupt take place, which will help
> saving power for us.
>
> And as the last patch described, to enable this support, an external
> timer is needed to avoid getting wrong system time when using the MIPS
> Timer, 'Cause the MIPS Timer's frequency is half of the cpu frequency,
> when the cpu frequency is changed, the MIPS Timer will be not accuracy.
>
> This version incorporates the feedback from "Dominik Brodowski
> <linux@dominikbrodowski.net>" to register transition notifier before
> register_driver().
Thanks, queue for 2.6.33.
Ralf
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2009-11-17 13:11 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-11-16 17:32 [PATCH v1 0/3] Add CPUFreq support for loongson2f Wu Zhangjin
[not found] ` <cover.1258392631.git.wuzhangjin@gmail.com>
2009-11-16 17:32 ` [PATCH v1 1/3] [loongson] lemote-2f: add cs5536 MFGPT timer support Wu Zhangjin
2009-11-17 13:10 ` Ralf Baechle
2009-11-16 17:32 ` [PATCH v1 2/3] MIPS: add basic options for CPUFreq support Wu Zhangjin
2009-11-17 13:10 ` Ralf Baechle
2009-11-16 17:32 ` [PATCH v1 3/3] [loongson] 2f: add " Wu Zhangjin
2009-11-17 13:10 ` Ralf Baechle
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).