// SPDX-License-Identifier: GPL-2.0-only /* * Cyrix MediaGX and NatSemi Geode Suspend Modulation * (C) 2002 Zwane Mwaikambo <zwane@commfireservices.com> * (C) 2002 Hiroshi Miura <miura@da-cha.org> * All Rights Reserved * * The author(s) of this software shall not be held liable for damages * of any nature resulting due to the use of this software. This * software is provided AS-IS with no warranties. * * Theoretical note: * * (see Geode(tm) CS5530 manual (rev.4.1) page.56) * * CPU frequency control on NatSemi Geode GX1/GXLV processor and CS55x0 * are based on Suspend Modulation. * * Suspend Modulation works by asserting and de-asserting the SUSP# pin * to CPU(GX1/GXLV) for configurable durations. When asserting SUSP# * the CPU enters an idle state. GX1 stops its core clock when SUSP# is * asserted then power consumption is reduced. * * Suspend Modulation's OFF/ON duration are configurable * with 'Suspend Modulation OFF Count Register' * and 'Suspend Modulation ON Count Register'. * These registers are 8bit counters that represent the number of * 32us intervals which the SUSP# pin is asserted(ON)/de-asserted(OFF) * to the processor. * * These counters define a ratio which is the effective frequency * of operation of the system. * * OFF Count * F_eff = Fgx * ---------------------- * OFF Count + ON Count * * 0 <= On Count, Off Count <= 255 * * From these limits, we can get register values * * off_duration + on_duration <= MAX_DURATION * on_duration = off_duration * (stock_freq - freq) / freq * * off_duration = (freq * DURATION) / stock_freq * on_duration = DURATION - off_duration * *--------------------------------------------------------------------------- * * ChangeLog: * Dec. 12, 2003 Hiroshi Miura <miura@da-cha.org> * - fix on/off register mistake * - fix cpu_khz calc when it stops cpu modulation. * * Dec. 11, 2002 Hiroshi Miura <miura@da-cha.org> * - rewrite for Cyrix MediaGX Cx5510/5520 and * NatSemi Geode Cs5530(A). * * Jul. ??, 2002 Zwane Mwaikambo <zwane@commfireservices.com> * - cs5530_mod patch for 2.4.19-rc1. * *--------------------------------------------------------------------------- * * Todo * Test on machines with 5510, 5530, 5530A
*/
/* PCI bus clock - defaults to 30.000 if cpu_khz is not available */ staticint pci_busclk;
module_param(pci_busclk, int, 0444);
/* maximum duration for which the cpu may be suspended * (32us * MAX_DURATION). If no parameter is given, this defaults * to 255. * Note that this leads to a maximum of 8 ms(!) where the CPU clock * is suspended -- processing power is just 0.39% of what it used to be,
* though. 781.25 kHz(!) for a 200 MHz processor -- wow. */ staticint max_duration = 255;
module_param(max_duration, int, 0444);
/* For the default policy, we want at least some processing power * - let's say 5%. (min = maxfreq / POLICY_MIN_DIV)
*/ #define POLICY_MIN_DIV 20
/** * we can detect a core multiplier from dir0_lsb * from GX1 datasheet p.56, * MULT[3:0]: * 0000 = SYSCLK multiplied by 4 (test only) * 0001 = SYSCLK multiplied by 10 * 0010 = SYSCLK multiplied by 4 * 0011 = SYSCLK multiplied by 6 * 0100 = SYSCLK multiplied by 9 * 0101 = SYSCLK multiplied by 5 * 0110 = SYSCLK multiplied by 7 * 0111 = SYSCLK multiplied by 8 * of 33.3MHz
**/ staticint gx_freq_mult[16] = {
4, 10, 4, 6, 9, 5, 7, 8,
0, 0, 0, 0, 0, 0, 0, 0
};
/* detect which companion chip is used */
for_each_pci_dev(gx_pci) { if ((pci_match_id(gx_chipset_tbl, gx_pci)) != NULL) return gx_pci;
}
pr_debug("error: no supported chipset found!\n"); return NULL;
}
/** * gx_get_cpuspeed: * * Finds out at which efficient frequency the Cyrix MediaGX/NatSemi * Geode CPU runs.
*/ staticunsignedint gx_get_cpuspeed(unsignedint cpu)
{ if ((gx_params->pci_suscfg & SUSMOD) == 0) return stock_freq;
if (new_khz != stock_freq) { /* if new khz == 100% of CPU speed, it is special case */ switch (gx_params->cs55x0->device) { case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
pmer1 = gx_params->pci_pmer1 | IRQ_SPDUP | VID_SPDUP; /* FIXME: need to test other values -- Zwane,Miura */ /* typical 2 to 4ms */
gx_write_byte(PCI_IRQTC, 4); /* typical 50 to 100ms */
gx_write_byte(PCI_VIDTC, 100);
gx_write_byte(PCI_PMER1, pmer1);
/**************************************************************** * High level functions *
****************************************************************/
/* * cpufreq_gx_verify: test if frequency range is valid * * This function checks if a given frequency range in kHz is valid * for the hardware supported by the driver.
*/
/* it needs to be assured that at least one supported frequency is * within policy->min and policy->max. If it is not, policy->max * needs to be increased until one frequency is supported. * policy->min may not be decreased, though. This way we guarantee a * specific processing capacity.
*/
tmp_freq = gx_validate_speed(policy->min, &tmp1, &tmp2); if (tmp_freq < policy->min)
tmp_freq += stock_freq / max_duration;
policy->min = tmp_freq; if (policy->min > policy->max)
policy->max = tmp_freq;
tmp_freq = gx_validate_speed(policy->max, &tmp1, &tmp2); if (tmp_freq > policy->max)
tmp_freq -= stock_freq / max_duration;
policy->max = tmp_freq; if (policy->max < policy->min)
policy->max = policy->min;
cpufreq_verify_within_limits(policy, (stock_freq / max_duration),
stock_freq);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.