cregit-Linux how code gets into the kernel

Release 4.7 drivers/cpufreq/elanfreq.c

Directory: drivers/cpufreq
/*
 *      elanfreq:       cpufreq driver for the AMD ELAN family
 *
 *      (c) Copyright 2002 Robert Schwebel <r.schwebel@pengutronix.de>
 *
 *      Parts of this code are (c) Sven Geggus <sven@geggus.net>
 *
 *      All Rights Reserved.
 *
 *      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.
 *
 *      2002-02-13: - initial revision for 2.4.18-pre9 by Robert Schwebel
 *
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>

#include <linux/delay.h>
#include <linux/cpufreq.h>

#include <asm/cpu_device_id.h>
#include <asm/msr.h>
#include <linux/timex.h>
#include <linux/io.h>


#define REG_CSCIR 0x22		
/* Chip Setup and Control Index Register    */

#define REG_CSCDR 0x23		
/* Chip Setup and Control Data  Register    */

/* Module parameter */

static int max_freq;


struct s_elan_multiplier {
	
int clock;		/* frequency in kHz                         */
	
int val40h;		/* PMU Force Mode register                  */
	
int val80h;		/* CPU Clock Speed Register                 */
};

/*
 * It is important that the frequencies
 * are listed in ascending order here!
 */

static struct s_elan_multiplier elan_multiplier[] = {
	{1000,	0x02,	0x18},
	{2000,	0x02,	0x10},
	{4000,	0x02,	0x08},
	{8000,	0x00,	0x00},
	{16000,	0x00,	0x02},
	{33000,	0x00,	0x04},
	{66000,	0x01,	0x04},
	{99000,	0x01,	0x05}
};


static struct cpufreq_frequency_table elanfreq_table[] = {
	{0, 0,	1000},
	{0, 1,	2000},
	{0, 2,	4000},
	{0, 3,	8000},
	{0, 4,	16000},
	{0, 5,	33000},
	{0, 6,	66000},
	{0, 7,	99000},
	{0, 0,	CPUFREQ_TABLE_END},
};


/**
 *      elanfreq_get_cpu_frequency: determine current cpu speed
 *
 *      Finds out at which frequency the CPU of the Elan SOC runs
 *      at the moment. Frequencies from 1 to 33 MHz are generated
 *      the normal way, 66 and 99 MHz are called "Hyperspeed Mode"
 *      and have the rest of the chip running with 33 MHz.
 */


static unsigned int elanfreq_get_cpu_frequency(unsigned int cpu) { u8 clockspeed_reg; /* Clock Speed Register */ local_irq_disable(); outb_p(0x80, REG_CSCIR); clockspeed_reg = inb_p(REG_CSCDR); local_irq_enable(); if ((clockspeed_reg & 0xE0) == 0xE0) return 0; /* Are we in CPU clock multiplied mode (66/99 MHz)? */ if ((clockspeed_reg & 0xE0) == 0xC0) { if ((clockspeed_reg & 0x01) == 0) return 66000; else return 99000; } /* 33 MHz is not 32 MHz... */ if ((clockspeed_reg & 0xE0) == 0xA0) return 33000; return (1<<((clockspeed_reg & 0xE0) >> 5)) * 1000; }

Contributors

PersonTokensPropCommitsCommitProp
dominik brodowskidominik brodowski10697.25%150.00%
dave jonesdave jones32.75%150.00%
Total109100.00%2100.00%


static int elanfreq_target(struct cpufreq_policy *policy, unsigned int state) { /* * Access to the Elan's internal registers is indexed via * 0x22: Chip Setup & Control Register Index Register (CSCI) * 0x23: Chip Setup & Control Register Data Register (CSCD) * */ /* * 0x40 is the Power Management Unit's Force Mode Register. * Bit 6 enables Hyperspeed Mode (66/100 MHz core frequency) */ local_irq_disable(); outb_p(0x40, REG_CSCIR); /* Disable hyperspeed mode */ outb_p(0x00, REG_CSCDR); local_irq_enable(); /* wait till internal pipelines and */ udelay(1000); /* buffers have cleaned up */ local_irq_disable(); /* now, set the CPU clock speed register (0x80) */ outb_p(0x80, REG_CSCIR); outb_p(elan_multiplier[state].val80h, REG_CSCDR); /* now, the hyperspeed bit in PMU Force Mode Register (0x40) */ outb_p(0x40, REG_CSCIR); outb_p(elan_multiplier[state].val40h, REG_CSCDR); udelay(10000); local_irq_enable(); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
dominik brodowskidominik brodowski8989.90%240.00%
viresh kumarviresh kumar77.07%240.00%
dave jonesdave jones33.03%120.00%
Total99100.00%5100.00%

/* * Module init and exit code */
static int elanfreq_cpu_init(struct cpufreq_policy *policy) { struct cpuinfo_x86 *c = &cpu_data(0); struct cpufreq_frequency_table *pos; /* capability check */ if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 4) || (c->x86_model != 10)) return -ENODEV; /* max freq */ if (!max_freq) max_freq = elanfreq_get_cpu_frequency(0); /* table init */ cpufreq_for_each_entry(pos, elanfreq_table) if (pos->frequency > max_freq) pos->frequency = CPUFREQ_ENTRY_INVALID; /* cpuinfo and default policy values */ policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; return cpufreq_table_validate_and_show(policy, elanfreq_table); }

Contributors

PersonTokensPropCommitsCommitProp
dominik brodowskidominik brodowski8376.15%337.50%
stratos karafotisstratos karafotis1412.84%112.50%
dave jonesdave jones65.50%225.00%
mike travismike travis43.67%112.50%
viresh kumarviresh kumar21.83%112.50%
Total109100.00%8100.00%

#ifndef MODULE /** * elanfreq_setup - elanfreq command line parameter parsing * * elanfreq command line parameter. Use: * elanfreq=66000 * to set the maximum CPU frequency to 66 MHz. Note that in * case you do not give this boot parameter, the maximum * frequency will fall back to _current_ CPU frequency which * might be lower. If you build this as a module, use the * max_freq module parameter instead. */
static int __init elanfreq_setup(char *str) { max_freq = simple_strtoul(str, &str, 0); pr_warn("You're using the deprecated elanfreq command line option. Use elanfreq.max_freq instead, please!\n"); return 1; }

Contributors

PersonTokensPropCommitsCommitProp
dominik brodowskidominik brodowski2683.87%360.00%
dave jonesdave jones412.90%120.00%
joe perchesjoe perches13.23%120.00%
Total31100.00%5100.00%

__setup("elanfreq=", elanfreq_setup); #endif static struct cpufreq_driver elanfreq_driver = { .get = elanfreq_get_cpu_frequency, .verify = cpufreq_generic_frequency_table_verify, .target_index = elanfreq_target, .init = elanfreq_cpu_init, .name = "elanfreq", .attr = cpufreq_generic_attr, }; static const struct x86_cpu_id elan_id[] = { { X86_VENDOR_AMD, 4, 10, }, {} }; MODULE_DEVICE_TABLE(x86cpu, elan_id);
static int __init elanfreq_init(void) { if (!x86_match_cpu(elan_id)) return -ENODEV; return cpufreq_register_driver(&elanfreq_driver); }

Contributors

PersonTokensPropCommitsCommitProp
dominik brodowskidominik brodowski2485.71%266.67%
andi kleenandi kleen414.29%133.33%
Total28100.00%3100.00%


static void __exit elanfreq_exit(void) { cpufreq_unregister_driver(&elanfreq_driver); }

Contributors

PersonTokensPropCommitsCommitProp
dominik brodowskidominik brodowski15100.00%2100.00%
Total15100.00%2100.00%

module_param(max_freq, int, 0444); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Robert Schwebel <r.schwebel@pengutronix.de>, " "Sven Geggus <sven@geggus.net>"); MODULE_DESCRIPTION("cpufreq driver for AMD's Elan CPUs"); module_init(elanfreq_init); module_exit(elanfreq_exit);

Overall Contributors

PersonTokensPropCommitsCommitProp
dominik brodowskidominik brodowski59882.60%521.74%
dave jonesdave jones354.83%730.43%
andi kleenandi kleen334.56%14.35%
viresh kumarviresh kumar304.14%521.74%
stratos karafotisstratos karafotis141.93%14.35%
joe perchesjoe perches81.10%28.70%
mike travismike travis40.55%14.35%
paolo ciarrocchipaolo ciarrocchi20.28%14.35%
Total724100.00%23100.00%
Directory: drivers/cpufreq
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}