Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  *	Cyrix MediaGX and NatSemi Geode Suspend Modulation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *	(C) 2002 Zwane Mwaikambo <zwane@commfireservices.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  *	(C) 2002 Hiroshi Miura   <miura@da-cha.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *	All Rights Reserved
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  *      The author(s) of this software shall not be held liable for damages
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  *      of any nature resulting due to the use of this software. This
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  *      software is provided AS-IS with no warranties.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  * Theoretical note:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14)  *	(see Geode(tm) CS5530 manual (rev.4.1) page.56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16)  *	CPU frequency control on NatSemi Geode GX1/GXLV processor and CS55x0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17)  *	are based on Suspend Modulation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19)  *	Suspend Modulation works by asserting and de-asserting the SUSP# pin
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20)  *	to CPU(GX1/GXLV) for configurable durations. When asserting SUSP#
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21)  *	the CPU enters an idle state. GX1 stops its core clock when SUSP# is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22)  *	asserted then power consumption is reduced.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24)  *	Suspend Modulation's OFF/ON duration are configurable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25)  *	with 'Suspend Modulation OFF Count Register'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26)  *	and 'Suspend Modulation ON Count Register'.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27)  *	These registers are 8bit counters that represent the number of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28)  *	32us intervals which the SUSP# pin is asserted(ON)/de-asserted(OFF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29)  *	to the processor.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31)  *	These counters define a ratio which is the effective frequency
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32)  *	of operation of the system.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34)  *			       OFF Count
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35)  *	F_eff = Fgx * ----------------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36)  *	                OFF Count + ON Count
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38)  *	0 <= On Count, Off Count <= 255
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40)  *	From these limits, we can get register values
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42)  *	off_duration + on_duration <= MAX_DURATION
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43)  *	on_duration = off_duration * (stock_freq - freq) / freq
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45)  *      off_duration  =  (freq * DURATION) / stock_freq
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46)  *      on_duration = DURATION - off_duration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48)  *---------------------------------------------------------------------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50)  * ChangeLog:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51)  *	Dec. 12, 2003	Hiroshi Miura <miura@da-cha.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52)  *		- fix on/off register mistake
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53)  *		- fix cpu_khz calc when it stops cpu modulation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55)  *	Dec. 11, 2002	Hiroshi Miura <miura@da-cha.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56)  *		- rewrite for Cyrix MediaGX Cx5510/5520 and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57)  *		  NatSemi Geode Cs5530(A).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59)  *	Jul. ??, 2002  Zwane Mwaikambo <zwane@commfireservices.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60)  *		- cs5530_mod patch for 2.4.19-rc1.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62)  *---------------------------------------------------------------------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64)  * Todo
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65)  *	Test on machines with 5510, 5530, 5530A
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) /************************************************************************
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69)  *			Suspend Modulation - Definitions		*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70)  ************************************************************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) #include <linux/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) #include <linux/cpufreq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) #include <asm/cpu_device_id.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) #include <asm/processor-cyrix.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) /* PCI config registers, all at F0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) #define PCI_PMER1	0x80	/* power management enable register 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) #define PCI_PMER2	0x81	/* power management enable register 2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) #define PCI_PMER3	0x82	/* power management enable register 3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) #define PCI_IRQTC	0x8c	/* irq speedup timer counter register:typical 2 to 4ms */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) #define PCI_VIDTC	0x8d	/* video speedup timer counter register: typical 50 to 100ms */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) #define PCI_MODOFF	0x94	/* suspend modulation OFF counter register, 1 = 32us */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) #define PCI_MODON	0x95	/* suspend modulation ON counter register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) #define PCI_SUSCFG	0x96	/* suspend configuration register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) /* PMER1 bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) #define GPM		(1<<0)	/* global power management */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) #define GIT		(1<<1)	/* globally enable PM device idle timers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) #define GTR		(1<<2)	/* globally enable IO traps */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) #define IRQ_SPDUP	(1<<3)	/* disable clock throttle during interrupt handling */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) #define VID_SPDUP	(1<<4)	/* disable clock throttle during vga video handling */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) /* SUSCFG bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) #define SUSMOD		(1<<0)	/* enable/disable suspend modulation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) /* the below is supported only with cs5530 (after rev.1.2)/cs5530A */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) #define SMISPDUP	(1<<1)	/* select how SMI re-enable suspend modulation: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 				/* IRQTC timer or read SMI speedup disable reg.(F1BAR[08-09h]) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) #define SUSCFG		(1<<2)	/* enable powering down a GXLV processor. "Special 3Volt Suspend" mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) /* the below is supported only with cs5530A */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) #define PWRSVE_ISA	(1<<3)	/* stop ISA clock  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) #define PWRSVE		(1<<4)	/* active idle */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) struct gxfreq_params {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 	u8 on_duration;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	u8 off_duration;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 	u8 pci_suscfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	u8 pci_pmer1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 	u8 pci_pmer2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	struct pci_dev *cs55x0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) static struct gxfreq_params *gx_params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static int stock_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) /* PCI bus clock - defaults to 30.000 if cpu_khz is not available */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) static int pci_busclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) module_param(pci_busclk, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) /* maximum duration for which the cpu may be suspended
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)  * (32us * MAX_DURATION). If no parameter is given, this defaults
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)  * to 255.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)  * Note that this leads to a maximum of 8 ms(!) where the CPU clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)  * is suspended -- processing power is just 0.39% of what it used to be,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)  * though. 781.25 kHz(!) for a 200 MHz processor -- wow. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) static int max_duration = 255;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) module_param(max_duration, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) /* For the default policy, we want at least some processing power
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)  * - let's say 5%. (min = maxfreq / POLICY_MIN_DIV)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) #define POLICY_MIN_DIV 20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)  * we can detect a core multiplier from dir0_lsb
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)  * from GX1 datasheet p.56,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)  *	MULT[3:0]:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)  *	0000 = SYSCLK multiplied by 4 (test only)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)  *	0001 = SYSCLK multiplied by 10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)  *	0010 = SYSCLK multiplied by 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)  *	0011 = SYSCLK multiplied by 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)  *	0100 = SYSCLK multiplied by 9
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)  *	0101 = SYSCLK multiplied by 5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)  *	0110 = SYSCLK multiplied by 7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)  *	0111 = SYSCLK multiplied by 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)  *              of 33.3MHz
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)  **/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) static int gx_freq_mult[16] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 		4, 10, 4, 6, 9, 5, 7, 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 		0, 0, 0, 0, 0, 0, 0, 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) /****************************************************************
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)  *	Low Level chipset interface				*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)  ****************************************************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) static struct pci_device_id gx_chipset_tbl[] __initdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 	{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY), },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5520), },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 	{ 0, },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) MODULE_DEVICE_TABLE(pci, gx_chipset_tbl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) static void gx_write_byte(int reg, int value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 	pci_write_config_byte(gx_params->cs55x0, reg, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)  * gx_detect_chipset:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)  **/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) static struct pci_dev * __init gx_detect_chipset(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 	struct pci_dev *gx_pci = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 	/* detect which companion chip is used */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 	for_each_pci_dev(gx_pci) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 		if ((pci_match_id(gx_chipset_tbl, gx_pci)) != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 			return gx_pci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 	pr_debug("error: no supported chipset found!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)  * gx_get_cpuspeed:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)  * Finds out at which efficient frequency the Cyrix MediaGX/NatSemi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)  * Geode CPU runs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) static unsigned int gx_get_cpuspeed(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 	if ((gx_params->pci_suscfg & SUSMOD) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 		return stock_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 	return (stock_freq * gx_params->off_duration)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 		/ (gx_params->on_duration + gx_params->off_duration);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)  *      gx_validate_speed:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)  *      determine current cpu speed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)  **/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) static unsigned int gx_validate_speed(unsigned int khz, u8 *on_duration,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 		u8 *off_duration)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 	unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 	u8 tmp_on, tmp_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 	int old_tmp_freq = stock_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 	int tmp_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 	*off_duration = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 	*on_duration = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 	for (i = max_duration; i > 0; i--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 		tmp_off = ((khz * i) / stock_freq) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 		tmp_on = i - tmp_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 		tmp_freq = (stock_freq * tmp_off) / i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 		/* if this relation is closer to khz, use this. If it's equal,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 		 * prefer it, too - lower latency */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 		if (abs(tmp_freq - khz) <= abs(old_tmp_freq - khz)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 			*on_duration = tmp_on;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 			*off_duration = tmp_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 			old_tmp_freq = tmp_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 	return old_tmp_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)  * gx_set_cpuspeed:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)  * set cpu speed in khz.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)  **/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) static void gx_set_cpuspeed(struct cpufreq_policy *policy, unsigned int khz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 	u8 suscfg, pmer1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 	unsigned int new_khz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 	unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 	struct cpufreq_freqs freqs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 	freqs.old = gx_get_cpuspeed(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 	new_khz = gx_validate_speed(khz, &gx_params->on_duration,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 			&gx_params->off_duration);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 	freqs.new = new_khz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 	cpufreq_freq_transition_begin(policy, &freqs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 	local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 	if (new_khz != stock_freq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 		/* if new khz == 100% of CPU speed, it is special case */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 		switch (gx_params->cs55x0->device) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 		case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 			pmer1 = gx_params->pci_pmer1 | IRQ_SPDUP | VID_SPDUP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 			/* FIXME: need to test other values -- Zwane,Miura */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 			/* typical 2 to 4ms */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 			gx_write_byte(PCI_IRQTC, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 			/* typical 50 to 100ms */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 			gx_write_byte(PCI_VIDTC, 100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 			gx_write_byte(PCI_PMER1, pmer1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 			if (gx_params->cs55x0->revision < 0x10) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 				/* CS5530(rev 1.2, 1.3) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 				suscfg = gx_params->pci_suscfg|SUSMOD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 			} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 				/* CS5530A,B.. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 				suscfg = gx_params->pci_suscfg|SUSMOD|PWRSVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 		case PCI_DEVICE_ID_CYRIX_5520:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 		case PCI_DEVICE_ID_CYRIX_5510:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 			suscfg = gx_params->pci_suscfg | SUSMOD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 		default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 			local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 			pr_debug("fatal: try to set unknown chipset.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 			return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 		suscfg = gx_params->pci_suscfg & ~(SUSMOD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 		gx_params->off_duration = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 		gx_params->on_duration = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 		pr_debug("suspend modulation disabled: cpu runs 100%% speed.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 	gx_write_byte(PCI_MODOFF, gx_params->off_duration);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 	gx_write_byte(PCI_MODON, gx_params->on_duration);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 	gx_write_byte(PCI_SUSCFG, suscfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 	pci_read_config_byte(gx_params->cs55x0, PCI_SUSCFG, &suscfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 	local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 	gx_params->pci_suscfg = suscfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 	cpufreq_freq_transition_end(policy, &freqs, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 	pr_debug("suspend modulation w/ duration of ON:%d us, OFF:%d us\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 		gx_params->on_duration * 32, gx_params->off_duration * 32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 	pr_debug("suspend modulation w/ clock speed: %d kHz.\n", freqs.new);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) /****************************************************************
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)  *             High level functions                             *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)  ****************************************************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)  *	cpufreq_gx_verify: test if frequency range is valid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)  *	This function checks if a given frequency range in kHz is valid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)  *      for the hardware supported by the driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) static int cpufreq_gx_verify(struct cpufreq_policy_data *policy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 	unsigned int tmp_freq = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 	u8 tmp1, tmp2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 	if (!stock_freq || !policy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 	policy->cpu = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 	cpufreq_verify_within_limits(policy, (stock_freq / max_duration),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 			stock_freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 	/* it needs to be assured that at least one supported frequency is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 	 * within policy->min and policy->max. If it is not, policy->max
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 	 * needs to be increased until one frequency is supported.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 	 * policy->min may not be decreased, though. This way we guarantee a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 	 * specific processing capacity.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 	tmp_freq = gx_validate_speed(policy->min, &tmp1, &tmp2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 	if (tmp_freq < policy->min)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 		tmp_freq += stock_freq / max_duration;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 	policy->min = tmp_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 	if (policy->min > policy->max)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 		policy->max = tmp_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 	tmp_freq = gx_validate_speed(policy->max, &tmp1, &tmp2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 	if (tmp_freq > policy->max)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 		tmp_freq -= stock_freq / max_duration;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 	policy->max = tmp_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 	if (policy->max < policy->min)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 		policy->max = policy->min;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 	cpufreq_verify_within_limits(policy, (stock_freq / max_duration),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 			stock_freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)  *      cpufreq_gx_target:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) static int cpufreq_gx_target(struct cpufreq_policy *policy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 			     unsigned int target_freq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 			     unsigned int relation)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 	u8 tmp1, tmp2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 	unsigned int tmp_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 	if (!stock_freq || !policy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 	policy->cpu = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 	tmp_freq = gx_validate_speed(target_freq, &tmp1, &tmp2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 	while (tmp_freq < policy->min) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 		tmp_freq += stock_freq / max_duration;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 		tmp_freq = gx_validate_speed(tmp_freq, &tmp1, &tmp2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 	while (tmp_freq > policy->max) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 		tmp_freq -= stock_freq / max_duration;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) 		tmp_freq = gx_validate_speed(tmp_freq, &tmp1, &tmp2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 	gx_set_cpuspeed(policy, tmp_freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 	unsigned int maxfreq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 	if (!policy || policy->cpu != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) 		return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) 	/* determine maximum frequency */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) 	if (pci_busclk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 		maxfreq = pci_busclk * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 	else if (cpu_khz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 		maxfreq = cpu_khz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 		maxfreq = 30000 * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 	stock_freq = maxfreq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 	pr_debug("cpu max frequency is %d.\n", maxfreq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) 	/* setup basic struct for cpufreq API */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 	policy->cpu = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 	if (max_duration < POLICY_MIN_DIV)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 		policy->min = maxfreq / max_duration;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 		policy->min = maxfreq / POLICY_MIN_DIV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) 	policy->max = maxfreq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 	policy->cpuinfo.min_freq = maxfreq / max_duration;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) 	policy->cpuinfo.max_freq = maxfreq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)  * cpufreq_gx_init:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433)  *   MediaGX/Geode GX initialize cpufreq driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) static struct cpufreq_driver gx_suspmod_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) 	.flags		= CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 	.get		= gx_get_cpuspeed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) 	.verify		= cpufreq_gx_verify,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) 	.target		= cpufreq_gx_target,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) 	.init		= cpufreq_gx_cpu_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) 	.name		= "gx-suspmod",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) static int __init cpufreq_gx_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) 	struct gxfreq_params *params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) 	struct pci_dev *gx_pci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) 	/* Test if we have the right hardware */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) 	gx_pci = gx_detect_chipset();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) 	if (gx_pci == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) 		return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) 	/* check whether module parameters are sane */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) 	if (max_duration > 0xff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) 		max_duration = 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) 	pr_debug("geode suspend modulation available.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) 	params = kzalloc(sizeof(*params), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) 	if (params == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) 	params->cs55x0 = gx_pci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) 	gx_params = params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) 	/* keep cs55x0 configurations */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) 	pci_read_config_byte(params->cs55x0, PCI_SUSCFG, &(params->pci_suscfg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) 	pci_read_config_byte(params->cs55x0, PCI_PMER1, &(params->pci_pmer1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) 	pci_read_config_byte(params->cs55x0, PCI_PMER2, &(params->pci_pmer2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) 	pci_read_config_byte(params->cs55x0, PCI_MODON, &(params->on_duration));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) 	pci_read_config_byte(params->cs55x0, PCI_MODOFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 			&(params->off_duration));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 	ret = cpufreq_register_driver(&gx_suspmod_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) 	if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) 		kfree(params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) 		return ret;                   /* register error! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) static void __exit cpufreq_gx_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) 	cpufreq_unregister_driver(&gx_suspmod_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) 	pci_dev_put(gx_params->cs55x0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) 	kfree(gx_params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) MODULE_AUTHOR("Hiroshi Miura <miura@da-cha.org>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) MODULE_DESCRIPTION("Cpufreq driver for Cyrix MediaGX and NatSemi Geode");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) module_init(cpufreq_gx_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) module_exit(cpufreq_gx_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)