Linux Audio

Check our new training course

Loading...
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 *	sc520_freq.c: cpufreq driver for the AMD Elan sc520
  4 *
  5 *	Copyright (C) 2005 Sean Young <sean@mess.org>
  6 *
  7 *	Based on elanfreq.c
  8 *
  9 *	2005-03-30: - initial revision
 10 */
 11
 12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 13
 14#include <linux/kernel.h>
 15#include <linux/module.h>
 16#include <linux/init.h>
 17
 18#include <linux/delay.h>
 19#include <linux/cpufreq.h>
 20#include <linux/timex.h>
 21#include <linux/io.h>
 22
 23#include <asm/cpu_device_id.h>
 24#include <asm/msr.h>
 25
 26#define MMCR_BASE	0xfffef000	/* The default base address */
 27#define OFFS_CPUCTL	0x2   /* CPU Control Register */
 28
 29static __u8 __iomem *cpuctl;
 30
 31static struct cpufreq_frequency_table sc520_freq_table[] = {
 32	{0, 0x01,	100000},
 33	{0, 0x02,	133000},
 34	{0, 0,	CPUFREQ_TABLE_END},
 35};
 36
 37static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu)
 38{
 39	u8 clockspeed_reg = *cpuctl;
 40
 41	switch (clockspeed_reg & 0x03) {
 42	default:
 43		pr_err("error: cpuctl register has unexpected value %02x\n",
 44		       clockspeed_reg);
 45		fallthrough;
 46	case 0x01:
 47		return 100000;
 48	case 0x02:
 49		return 133000;
 50	}
 51}
 52
 53static int sc520_freq_target(struct cpufreq_policy *policy, unsigned int state)
 54{
 55
 56	u8 clockspeed_reg;
 57
 58	local_irq_disable();
 59
 60	clockspeed_reg = *cpuctl & ~0x03;
 61	*cpuctl = clockspeed_reg | sc520_freq_table[state].driver_data;
 62
 63	local_irq_enable();
 64
 65	return 0;
 66}
 67
 68/*
 69 *	Module init and exit code
 70 */
 71
 72static int sc520_freq_cpu_init(struct cpufreq_policy *policy)
 73{
 74	struct cpuinfo_x86 *c = &cpu_data(0);
 75
 76	/* capability check */
 77	if (c->x86_vendor != X86_VENDOR_AMD ||
 78	    c->x86 != 4 || c->x86_model != 9)
 79		return -ENODEV;
 80
 81	/* cpuinfo and default policy values */
 82	policy->cpuinfo.transition_latency = 1000000; /* 1ms */
 83	policy->freq_table = sc520_freq_table;
 84
 85	return 0;
 86}
 87
 88
 89static struct cpufreq_driver sc520_freq_driver = {
 90	.get	= sc520_freq_get_cpu_frequency,
 91	.verify	= cpufreq_generic_frequency_table_verify,
 92	.target_index = sc520_freq_target,
 93	.init	= sc520_freq_cpu_init,
 94	.name	= "sc520_freq",
 95	.attr	= cpufreq_generic_attr,
 96};
 97
 98static const struct x86_cpu_id sc520_ids[] = {
 99	X86_MATCH_VENDOR_FAM_MODEL(AMD, 4, 9, NULL),
100	{}
101};
102MODULE_DEVICE_TABLE(x86cpu, sc520_ids);
103
104static int __init sc520_freq_init(void)
105{
106	int err;
107
108	if (!x86_match_cpu(sc520_ids))
109		return -ENODEV;
110
111	cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1);
112	if (!cpuctl) {
113		pr_err("sc520_freq: error: failed to remap memory\n");
114		return -ENOMEM;
115	}
116
117	err = cpufreq_register_driver(&sc520_freq_driver);
118	if (err)
119		iounmap(cpuctl);
120
121	return err;
122}
123
124
125static void __exit sc520_freq_exit(void)
126{
127	cpufreq_unregister_driver(&sc520_freq_driver);
128	iounmap(cpuctl);
129}
130
131
132MODULE_LICENSE("GPL");
133MODULE_AUTHOR("Sean Young <sean@mess.org>");
134MODULE_DESCRIPTION("cpufreq driver for AMD's Elan sc520 CPU");
135
136module_init(sc520_freq_init);
137module_exit(sc520_freq_exit);
138
  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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 17
 18#include <linux/kernel.h>
 19#include <linux/module.h>
 20#include <linux/init.h>
 21
 22#include <linux/delay.h>
 23#include <linux/cpufreq.h>
 24#include <linux/timex.h>
 25#include <linux/io.h>
 26
 27#include <asm/cpu_device_id.h>
 28#include <asm/msr.h>
 29
 30#define MMCR_BASE	0xfffef000	/* The default base address */
 31#define OFFS_CPUCTL	0x2   /* CPU Control Register */
 32
 33static __u8 __iomem *cpuctl;
 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		pr_err("error: cpuctl register has unexpected value %02x\n",
 48		       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	policy->freq_table = sc520_freq_table;
 87
 88	return 0;
 89}
 90
 91
 92static struct cpufreq_driver sc520_freq_driver = {
 93	.get	= sc520_freq_get_cpu_frequency,
 94	.verify	= cpufreq_generic_frequency_table_verify,
 95	.target_index = sc520_freq_target,
 96	.init	= sc520_freq_cpu_init,
 97	.name	= "sc520_freq",
 98	.attr	= cpufreq_generic_attr,
 99};
100
101static const struct x86_cpu_id sc520_ids[] = {
102	{ X86_VENDOR_AMD, 4, 9 },
103	{}
104};
105MODULE_DEVICE_TABLE(x86cpu, sc520_ids);
106
107static int __init sc520_freq_init(void)
108{
109	int err;
110
111	if (!x86_match_cpu(sc520_ids))
112		return -ENODEV;
113
114	cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1);
115	if (!cpuctl) {
116		pr_err("sc520_freq: error: failed to remap memory\n");
117		return -ENOMEM;
118	}
119
120	err = cpufreq_register_driver(&sc520_freq_driver);
121	if (err)
122		iounmap(cpuctl);
123
124	return err;
125}
126
127
128static void __exit sc520_freq_exit(void)
129{
130	cpufreq_unregister_driver(&sc520_freq_driver);
131	iounmap(cpuctl);
132}
133
134
135MODULE_LICENSE("GPL");
136MODULE_AUTHOR("Sean Young <sean@mess.org>");
137MODULE_DESCRIPTION("cpufreq driver for AMD's Elan sc520 CPU");
138
139module_init(sc520_freq_init);
140module_exit(sc520_freq_exit);
141