File Index
Files and directories
Sign in
FILE

sc520_freq.c

File preview with syntax highlighting.

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