brintos

brintos / linux-shallow public Read only

0
0
Text · 4.1 KiB · 6a8e978 Raw
179 lines · c
1/*2 * Cpufreq driver for the loongson-2 processors3 *4 * The 2E revision of loongson processor not support this feature.5 *6 * Copyright (C) 2006 - 2008 Lemote Inc. & Institute of Computing Technology7 * Author: Yanhua, yanh@lemote.com8 *9 * This file is subject to the terms and conditions of the GNU General Public10 * License.  See the file "COPYING" in the main directory of this archive11 * for more details.12 */13 14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt15 16#include <linux/cpufreq.h>17#include <linux/module.h>18#include <linux/err.h>19#include <linux/delay.h>20#include <linux/platform_device.h>21 22#include <asm/idle.h>23 24#include <asm/mach-loongson2ef/loongson.h>25 26static uint nowait;27 28static void (*saved_cpu_wait) (void);29 30static int loongson2_cpu_freq_notifier(struct notifier_block *nb,31					unsigned long val, void *data);32 33static struct notifier_block loongson2_cpufreq_notifier_block = {34	.notifier_call = loongson2_cpu_freq_notifier35};36 37static int loongson2_cpu_freq_notifier(struct notifier_block *nb,38					unsigned long val, void *data)39{40	if (val == CPUFREQ_POSTCHANGE)41		current_cpu_data.udelay_val = loops_per_jiffy;42 43	return 0;44}45 46/*47 * Here we notify other drivers of the proposed change and the final change.48 */49static int loongson2_cpufreq_target(struct cpufreq_policy *policy,50				     unsigned int index)51{52	unsigned int freq;53 54	freq =55	    ((cpu_clock_freq / 1000) *56	     loongson2_clockmod_table[index].driver_data) / 8;57 58	/* setting the cpu frequency */59	loongson2_cpu_set_rate(freq);60 61	return 0;62}63 64static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy)65{66	int i;67	unsigned long rate;68	int ret;69 70	rate = cpu_clock_freq / 1000;71	if (!rate)72		return -EINVAL;73 74	/* clock table init */75	for (i = 2;76	     (loongson2_clockmod_table[i].frequency != CPUFREQ_TABLE_END);77	     i++)78		loongson2_clockmod_table[i].frequency = (rate * i) / 8;79 80	ret = loongson2_cpu_set_rate(rate);81	if (ret)82		return ret;83 84	cpufreq_generic_init(policy, &loongson2_clockmod_table[0], 0);85	return 0;86}87 88static struct cpufreq_driver loongson2_cpufreq_driver = {89	.name = "loongson2",90	.init = loongson2_cpufreq_cpu_init,91	.verify = cpufreq_generic_frequency_table_verify,92	.target_index = loongson2_cpufreq_target,93	.get = cpufreq_generic_get,94	.attr = cpufreq_generic_attr,95};96 97static const struct platform_device_id platform_device_ids[] = {98	{99		.name = "loongson2_cpufreq",100	},101	{}102};103 104MODULE_DEVICE_TABLE(platform, platform_device_ids);105 106static struct platform_driver platform_driver = {107	.driver = {108		.name = "loongson2_cpufreq",109	},110	.id_table = platform_device_ids,111};112 113/*114 * This is the simple version of Loongson-2 wait, Maybe we need do this in115 * interrupt disabled context.116 */117 118static DEFINE_SPINLOCK(loongson2_wait_lock);119 120static void loongson2_cpu_wait(void)121{122	unsigned long flags;123	u32 cpu_freq;124 125	spin_lock_irqsave(&loongson2_wait_lock, flags);126	cpu_freq = readl(LOONGSON_CHIPCFG);127	/* Put CPU into wait mode */128	writel(readl(LOONGSON_CHIPCFG) & ~0x7, LOONGSON_CHIPCFG);129	/* Restore CPU state */130	writel(cpu_freq, LOONGSON_CHIPCFG);131	spin_unlock_irqrestore(&loongson2_wait_lock, flags);132	local_irq_enable();133}134 135static int __init cpufreq_init(void)136{137	int ret;138 139	/* Register platform stuff */140	ret = platform_driver_register(&platform_driver);141	if (ret)142		return ret;143 144	pr_info("Loongson-2F CPU frequency driver\n");145 146	cpufreq_register_notifier(&loongson2_cpufreq_notifier_block,147				  CPUFREQ_TRANSITION_NOTIFIER);148 149	ret = cpufreq_register_driver(&loongson2_cpufreq_driver);150 151	if (!ret && !nowait) {152		saved_cpu_wait = cpu_wait;153		cpu_wait = loongson2_cpu_wait;154	}155 156	return ret;157}158 159static void __exit cpufreq_exit(void)160{161	if (!nowait && saved_cpu_wait)162		cpu_wait = saved_cpu_wait;163	cpufreq_unregister_driver(&loongson2_cpufreq_driver);164	cpufreq_unregister_notifier(&loongson2_cpufreq_notifier_block,165				    CPUFREQ_TRANSITION_NOTIFIER);166 167	platform_driver_unregister(&platform_driver);168}169 170module_init(cpufreq_init);171module_exit(cpufreq_exit);172 173module_param(nowait, uint, 0644);174MODULE_PARM_DESC(nowait, "Disable Loongson-2F specific wait");175 176MODULE_AUTHOR("Yanhua <yanh@lemote.com>");177MODULE_DESCRIPTION("cpufreq driver for Loongson2F");178MODULE_LICENSE("GPL");179