Linux Audio

Check our new training course

Loading...
v3.1
  1/*
  2 *	sc520_freq.c: cpufreq driver for the AMD Elan sc520
  3 *
  4 *	Copyright (C) 2005 Sean Young <sean@mess.org>
  5 *
  6 *	This program is free software; you can redistribute it and/or
  7 *	modify it under the terms of the GNU General Public License
  8 *	as published by the Free Software Foundation; either version
  9 *	2 of the License, or (at your option) any later version.
 10 *
 11 *	Based on elanfreq.c
 12 *
 13 *	2005-03-30: - initial revision
 14 */
 15
 16#include <linux/kernel.h>
 17#include <linux/module.h>
 18#include <linux/init.h>
 19
 20#include <linux/delay.h>
 21#include <linux/cpufreq.h>
 22#include <linux/timex.h>
 23#include <linux/io.h>
 24
 
 25#include <asm/msr.h>
 26
 27#define MMCR_BASE	0xfffef000	/* The default base address */
 28#define OFFS_CPUCTL	0x2   /* CPU Control Register */
 29
 30static __u8 __iomem *cpuctl;
 31
 32#define PFX "sc520_freq: "
 33
 34static struct cpufreq_frequency_table sc520_freq_table[] = {
 35	{0x01,	100000},
 36	{0x02,	133000},
 37	{0,	CPUFREQ_TABLE_END},
 38};
 39
 40static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu)
 41{
 42	u8 clockspeed_reg = *cpuctl;
 43
 44	switch (clockspeed_reg & 0x03) {
 45	default:
 46		printk(KERN_ERR PFX "error: cpuctl register has unexpected "
 47				"value %02x\n", clockspeed_reg);
 48	case 0x01:
 49		return 100000;
 50	case 0x02:
 51		return 133000;
 52	}
 53}
 54
 55static void sc520_freq_set_cpu_state(unsigned int state)
 56{
 57
 58	struct cpufreq_freqs	freqs;
 59	u8 clockspeed_reg;
 60
 61	freqs.old = sc520_freq_get_cpu_frequency(0);
 62	freqs.new = sc520_freq_table[state].frequency;
 63	freqs.cpu = 0; /* AMD Elan is UP */
 64
 65	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 66
 67	pr_debug("attempting to set frequency to %i kHz\n",
 68			sc520_freq_table[state].frequency);
 69
 70	local_irq_disable();
 71
 72	clockspeed_reg = *cpuctl & ~0x03;
 73	*cpuctl = clockspeed_reg | sc520_freq_table[state].index;
 74
 75	local_irq_enable();
 76
 77	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 78};
 79
 80static int sc520_freq_verify(struct cpufreq_policy *policy)
 81{
 82	return cpufreq_frequency_table_verify(policy, &sc520_freq_table[0]);
 83}
 84
 85static int sc520_freq_target(struct cpufreq_policy *policy,
 86			    unsigned int target_freq,
 87			    unsigned int relation)
 88{
 89	unsigned int newstate = 0;
 90
 91	if (cpufreq_frequency_table_target(policy, sc520_freq_table,
 92				target_freq, relation, &newstate))
 93		return -EINVAL;
 94
 95	sc520_freq_set_cpu_state(newstate);
 96
 97	return 0;
 98}
 99
100
101/*
102 *	Module init and exit code
103 */
104
105static int sc520_freq_cpu_init(struct cpufreq_policy *policy)
106{
107	struct cpuinfo_x86 *c = &cpu_data(0);
108	int result;
109
110	/* capability check */
111	if (c->x86_vendor != X86_VENDOR_AMD ||
112	    c->x86 != 4 || c->x86_model != 9)
113		return -ENODEV;
114
115	/* cpuinfo and default policy values */
116	policy->cpuinfo.transition_latency = 1000000; /* 1ms */
117	policy->cur = sc520_freq_get_cpu_frequency(0);
118
119	result = cpufreq_frequency_table_cpuinfo(policy, sc520_freq_table);
120	if (result)
121		return result;
122
123	cpufreq_frequency_table_get_attr(sc520_freq_table, policy->cpu);
124
125	return 0;
126}
127
128
129static int sc520_freq_cpu_exit(struct cpufreq_policy *policy)
130{
131	cpufreq_frequency_table_put_attr(policy->cpu);
132	return 0;
133}
134
135
136static struct freq_attr *sc520_freq_attr[] = {
137	&cpufreq_freq_attr_scaling_available_freqs,
138	NULL,
139};
140
141
142static struct cpufreq_driver sc520_freq_driver = {
143	.get	= sc520_freq_get_cpu_frequency,
144	.verify	= sc520_freq_verify,
145	.target	= sc520_freq_target,
146	.init	= sc520_freq_cpu_init,
147	.exit	= sc520_freq_cpu_exit,
148	.name	= "sc520_freq",
149	.owner	= THIS_MODULE,
150	.attr	= sc520_freq_attr,
151};
152
 
 
 
 
 
153
154static int __init sc520_freq_init(void)
155{
156	struct cpuinfo_x86 *c = &cpu_data(0);
157	int err;
158
159	/* Test if we have the right hardware */
160	if (c->x86_vendor != X86_VENDOR_AMD ||
161	    c->x86 != 4 || c->x86_model != 9) {
162		pr_debug("no Elan SC520 processor found!\n");
163		return -ENODEV;
164	}
165	cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1);
166	if (!cpuctl) {
167		printk(KERN_ERR "sc520_freq: error: failed to remap memory\n");
168		return -ENOMEM;
169	}
170
171	err = cpufreq_register_driver(&sc520_freq_driver);
172	if (err)
173		iounmap(cpuctl);
174
175	return err;
176}
177
178
179static void __exit sc520_freq_exit(void)
180{
181	cpufreq_unregister_driver(&sc520_freq_driver);
182	iounmap(cpuctl);
183}
184
185
186MODULE_LICENSE("GPL");
187MODULE_AUTHOR("Sean Young <sean@mess.org>");
188MODULE_DESCRIPTION("cpufreq driver for AMD's Elan sc520 CPU");
189
190module_init(sc520_freq_init);
191module_exit(sc520_freq_exit);
192
v3.15
  1/*
  2 *	sc520_freq.c: cpufreq driver for the AMD Elan sc520
  3 *
  4 *	Copyright (C) 2005 Sean Young <sean@mess.org>
  5 *
  6 *	This program is free software; you can redistribute it and/or
  7 *	modify it under the terms of the GNU General Public License
  8 *	as published by the Free Software Foundation; either version
  9 *	2 of the License, or (at your option) any later version.
 10 *
 11 *	Based on elanfreq.c
 12 *
 13 *	2005-03-30: - initial revision
 14 */
 15
 16#include <linux/kernel.h>
 17#include <linux/module.h>
 18#include <linux/init.h>
 19
 20#include <linux/delay.h>
 21#include <linux/cpufreq.h>
 22#include <linux/timex.h>
 23#include <linux/io.h>
 24
 25#include <asm/cpu_device_id.h>
 26#include <asm/msr.h>
 27
 28#define MMCR_BASE	0xfffef000	/* The default base address */
 29#define OFFS_CPUCTL	0x2   /* CPU Control Register */
 30
 31static __u8 __iomem *cpuctl;
 32
 33#define PFX "sc520_freq: "
 34
 35static struct cpufreq_frequency_table sc520_freq_table[] = {
 36	{0, 0x01,	100000},
 37	{0, 0x02,	133000},
 38	{0, 0,	CPUFREQ_TABLE_END},
 39};
 40
 41static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu)
 42{
 43	u8 clockspeed_reg = *cpuctl;
 44
 45	switch (clockspeed_reg & 0x03) {
 46	default:
 47		printk(KERN_ERR PFX "error: cpuctl register has unexpected "
 48				"value %02x\n", clockspeed_reg);
 49	case 0x01:
 50		return 100000;
 51	case 0x02:
 52		return 133000;
 53	}
 54}
 55
 56static int sc520_freq_target(struct cpufreq_policy *policy, unsigned int state)
 57{
 58
 
 59	u8 clockspeed_reg;
 60
 
 
 
 
 
 
 
 
 
 61	local_irq_disable();
 62
 63	clockspeed_reg = *cpuctl & ~0x03;
 64	*cpuctl = clockspeed_reg | sc520_freq_table[state].driver_data;
 65
 66	local_irq_enable();
 67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 68	return 0;
 69}
 70
 
 71/*
 72 *	Module init and exit code
 73 */
 74
 75static int sc520_freq_cpu_init(struct cpufreq_policy *policy)
 76{
 77	struct cpuinfo_x86 *c = &cpu_data(0);
 
 78
 79	/* capability check */
 80	if (c->x86_vendor != X86_VENDOR_AMD ||
 81	    c->x86 != 4 || c->x86_model != 9)
 82		return -ENODEV;
 83
 84	/* cpuinfo and default policy values */
 85	policy->cpuinfo.transition_latency = 1000000; /* 1ms */
 
 
 
 
 
 
 
 86
 87	return cpufreq_table_validate_and_show(policy, sc520_freq_table);
 88}
 89
 90
 
 
 
 
 
 
 
 
 
 
 
 
 
 91static struct cpufreq_driver sc520_freq_driver = {
 92	.get	= sc520_freq_get_cpu_frequency,
 93	.verify	= cpufreq_generic_frequency_table_verify,
 94	.target_index = sc520_freq_target,
 95	.init	= sc520_freq_cpu_init,
 
 96	.name	= "sc520_freq",
 97	.attr	= cpufreq_generic_attr,
 
 98};
 99
100static const struct x86_cpu_id sc520_ids[] = {
101	{ X86_VENDOR_AMD, 4, 9 },
102	{}
103};
104MODULE_DEVICE_TABLE(x86cpu, sc520_ids);
105
106static int __init sc520_freq_init(void)
107{
 
108	int err;
109
110	if (!x86_match_cpu(sc520_ids))
 
 
 
111		return -ENODEV;
112
113	cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1);
114	if (!cpuctl) {
115		printk(KERN_ERR "sc520_freq: error: failed to remap memory\n");
116		return -ENOMEM;
117	}
118
119	err = cpufreq_register_driver(&sc520_freq_driver);
120	if (err)
121		iounmap(cpuctl);
122
123	return err;
124}
125
126
127static void __exit sc520_freq_exit(void)
128{
129	cpufreq_unregister_driver(&sc520_freq_driver);
130	iounmap(cpuctl);
131}
132
133
134MODULE_LICENSE("GPL");
135MODULE_AUTHOR("Sean Young <sean@mess.org>");
136MODULE_DESCRIPTION("cpufreq driver for AMD's Elan sc520 CPU");
137
138module_init(sc520_freq_init);
139module_exit(sc520_freq_exit);
140