^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)