0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072 #include <linux/kernel.h>
0073 #include <linux/module.h>
0074 #include <linux/init.h>
0075 #include <linux/smp.h>
0076 #include <linux/cpufreq.h>
0077 #include <linux/pci.h>
0078 #include <linux/errno.h>
0079 #include <linux/slab.h>
0080
0081 #include <asm/cpu_device_id.h>
0082 #include <asm/processor-cyrix.h>
0083
0084
0085 #define PCI_PMER1 0x80
0086 #define PCI_PMER2 0x81
0087 #define PCI_PMER3 0x82
0088 #define PCI_IRQTC 0x8c
0089 #define PCI_VIDTC 0x8d
0090 #define PCI_MODOFF 0x94
0091 #define PCI_MODON 0x95
0092 #define PCI_SUSCFG 0x96
0093
0094
0095 #define GPM (1<<0)
0096 #define GIT (1<<1)
0097 #define GTR (1<<2)
0098 #define IRQ_SPDUP (1<<3)
0099 #define VID_SPDUP (1<<4)
0100
0101
0102 #define SUSMOD (1<<0)
0103
0104 #define SMISPDUP (1<<1)
0105
0106 #define SUSCFG (1<<2)
0107
0108 #define PWRSVE_ISA (1<<3)
0109 #define PWRSVE (1<<4)
0110
0111 struct gxfreq_params {
0112 u8 on_duration;
0113 u8 off_duration;
0114 u8 pci_suscfg;
0115 u8 pci_pmer1;
0116 u8 pci_pmer2;
0117 struct pci_dev *cs55x0;
0118 };
0119
0120 static struct gxfreq_params *gx_params;
0121 static int stock_freq;
0122
0123
0124 static int pci_busclk;
0125 module_param(pci_busclk, int, 0444);
0126
0127
0128
0129
0130
0131
0132
0133 static int max_duration = 255;
0134 module_param(max_duration, int, 0444);
0135
0136
0137
0138
0139 #define POLICY_MIN_DIV 20
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156 static int gx_freq_mult[16] = {
0157 4, 10, 4, 6, 9, 5, 7, 8,
0158 0, 0, 0, 0, 0, 0, 0, 0
0159 };
0160
0161
0162
0163
0164
0165 static struct pci_device_id gx_chipset_tbl[] __initdata = {
0166 { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY), },
0167 { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5520), },
0168 { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), },
0169 { 0, },
0170 };
0171 MODULE_DEVICE_TABLE(pci, gx_chipset_tbl);
0172
0173 static void gx_write_byte(int reg, int value)
0174 {
0175 pci_write_config_byte(gx_params->cs55x0, reg, value);
0176 }
0177
0178
0179
0180
0181
0182 static struct pci_dev * __init gx_detect_chipset(void)
0183 {
0184 struct pci_dev *gx_pci = NULL;
0185
0186
0187 for_each_pci_dev(gx_pci) {
0188 if ((pci_match_id(gx_chipset_tbl, gx_pci)) != NULL)
0189 return gx_pci;
0190 }
0191
0192 pr_debug("error: no supported chipset found!\n");
0193 return NULL;
0194 }
0195
0196
0197
0198
0199
0200
0201
0202 static unsigned int gx_get_cpuspeed(unsigned int cpu)
0203 {
0204 if ((gx_params->pci_suscfg & SUSMOD) == 0)
0205 return stock_freq;
0206
0207 return (stock_freq * gx_params->off_duration)
0208 / (gx_params->on_duration + gx_params->off_duration);
0209 }
0210
0211
0212
0213
0214
0215
0216
0217 static unsigned int gx_validate_speed(unsigned int khz, u8 *on_duration,
0218 u8 *off_duration)
0219 {
0220 unsigned int i;
0221 u8 tmp_on, tmp_off;
0222 int old_tmp_freq = stock_freq;
0223 int tmp_freq;
0224
0225 *off_duration = 1;
0226 *on_duration = 0;
0227
0228 for (i = max_duration; i > 0; i--) {
0229 tmp_off = ((khz * i) / stock_freq) & 0xff;
0230 tmp_on = i - tmp_off;
0231 tmp_freq = (stock_freq * tmp_off) / i;
0232
0233
0234 if (abs(tmp_freq - khz) <= abs(old_tmp_freq - khz)) {
0235 *on_duration = tmp_on;
0236 *off_duration = tmp_off;
0237 old_tmp_freq = tmp_freq;
0238 }
0239 }
0240
0241 return old_tmp_freq;
0242 }
0243
0244
0245
0246
0247
0248
0249
0250 static void gx_set_cpuspeed(struct cpufreq_policy *policy, unsigned int khz)
0251 {
0252 u8 suscfg, pmer1;
0253 unsigned int new_khz;
0254 unsigned long flags;
0255 struct cpufreq_freqs freqs;
0256
0257 freqs.old = gx_get_cpuspeed(0);
0258
0259 new_khz = gx_validate_speed(khz, &gx_params->on_duration,
0260 &gx_params->off_duration);
0261
0262 freqs.new = new_khz;
0263
0264 cpufreq_freq_transition_begin(policy, &freqs);
0265 local_irq_save(flags);
0266
0267 if (new_khz != stock_freq) {
0268
0269 switch (gx_params->cs55x0->device) {
0270 case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
0271 pmer1 = gx_params->pci_pmer1 | IRQ_SPDUP | VID_SPDUP;
0272
0273
0274 gx_write_byte(PCI_IRQTC, 4);
0275
0276 gx_write_byte(PCI_VIDTC, 100);
0277 gx_write_byte(PCI_PMER1, pmer1);
0278
0279 if (gx_params->cs55x0->revision < 0x10) {
0280
0281 suscfg = gx_params->pci_suscfg|SUSMOD;
0282 } else {
0283
0284 suscfg = gx_params->pci_suscfg|SUSMOD|PWRSVE;
0285 }
0286 break;
0287 case PCI_DEVICE_ID_CYRIX_5520:
0288 case PCI_DEVICE_ID_CYRIX_5510:
0289 suscfg = gx_params->pci_suscfg | SUSMOD;
0290 break;
0291 default:
0292 local_irq_restore(flags);
0293 pr_debug("fatal: try to set unknown chipset.\n");
0294 return;
0295 }
0296 } else {
0297 suscfg = gx_params->pci_suscfg & ~(SUSMOD);
0298 gx_params->off_duration = 0;
0299 gx_params->on_duration = 0;
0300 pr_debug("suspend modulation disabled: cpu runs 100%% speed.\n");
0301 }
0302
0303 gx_write_byte(PCI_MODOFF, gx_params->off_duration);
0304 gx_write_byte(PCI_MODON, gx_params->on_duration);
0305
0306 gx_write_byte(PCI_SUSCFG, suscfg);
0307 pci_read_config_byte(gx_params->cs55x0, PCI_SUSCFG, &suscfg);
0308
0309 local_irq_restore(flags);
0310
0311 gx_params->pci_suscfg = suscfg;
0312
0313 cpufreq_freq_transition_end(policy, &freqs, 0);
0314
0315 pr_debug("suspend modulation w/ duration of ON:%d us, OFF:%d us\n",
0316 gx_params->on_duration * 32, gx_params->off_duration * 32);
0317 pr_debug("suspend modulation w/ clock speed: %d kHz.\n", freqs.new);
0318 }
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331 static int cpufreq_gx_verify(struct cpufreq_policy_data *policy)
0332 {
0333 unsigned int tmp_freq = 0;
0334 u8 tmp1, tmp2;
0335
0336 if (!stock_freq || !policy)
0337 return -EINVAL;
0338
0339 policy->cpu = 0;
0340 cpufreq_verify_within_limits(policy, (stock_freq / max_duration),
0341 stock_freq);
0342
0343
0344
0345
0346
0347
0348
0349 tmp_freq = gx_validate_speed(policy->min, &tmp1, &tmp2);
0350 if (tmp_freq < policy->min)
0351 tmp_freq += stock_freq / max_duration;
0352 policy->min = tmp_freq;
0353 if (policy->min > policy->max)
0354 policy->max = tmp_freq;
0355 tmp_freq = gx_validate_speed(policy->max, &tmp1, &tmp2);
0356 if (tmp_freq > policy->max)
0357 tmp_freq -= stock_freq / max_duration;
0358 policy->max = tmp_freq;
0359 if (policy->max < policy->min)
0360 policy->max = policy->min;
0361 cpufreq_verify_within_limits(policy, (stock_freq / max_duration),
0362 stock_freq);
0363
0364 return 0;
0365 }
0366
0367
0368
0369
0370
0371 static int cpufreq_gx_target(struct cpufreq_policy *policy,
0372 unsigned int target_freq,
0373 unsigned int relation)
0374 {
0375 u8 tmp1, tmp2;
0376 unsigned int tmp_freq;
0377
0378 if (!stock_freq || !policy)
0379 return -EINVAL;
0380
0381 policy->cpu = 0;
0382
0383 tmp_freq = gx_validate_speed(target_freq, &tmp1, &tmp2);
0384 while (tmp_freq < policy->min) {
0385 tmp_freq += stock_freq / max_duration;
0386 tmp_freq = gx_validate_speed(tmp_freq, &tmp1, &tmp2);
0387 }
0388 while (tmp_freq > policy->max) {
0389 tmp_freq -= stock_freq / max_duration;
0390 tmp_freq = gx_validate_speed(tmp_freq, &tmp1, &tmp2);
0391 }
0392
0393 gx_set_cpuspeed(policy, tmp_freq);
0394
0395 return 0;
0396 }
0397
0398 static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy)
0399 {
0400 unsigned int maxfreq;
0401
0402 if (!policy || policy->cpu != 0)
0403 return -ENODEV;
0404
0405
0406 if (pci_busclk)
0407 maxfreq = pci_busclk * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f];
0408 else if (cpu_khz)
0409 maxfreq = cpu_khz;
0410 else
0411 maxfreq = 30000 * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f];
0412
0413 stock_freq = maxfreq;
0414
0415 pr_debug("cpu max frequency is %d.\n", maxfreq);
0416
0417
0418 policy->cpu = 0;
0419
0420 if (max_duration < POLICY_MIN_DIV)
0421 policy->min = maxfreq / max_duration;
0422 else
0423 policy->min = maxfreq / POLICY_MIN_DIV;
0424 policy->max = maxfreq;
0425 policy->cpuinfo.min_freq = maxfreq / max_duration;
0426 policy->cpuinfo.max_freq = maxfreq;
0427
0428 return 0;
0429 }
0430
0431
0432
0433
0434
0435 static struct cpufreq_driver gx_suspmod_driver = {
0436 .flags = CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING,
0437 .get = gx_get_cpuspeed,
0438 .verify = cpufreq_gx_verify,
0439 .target = cpufreq_gx_target,
0440 .init = cpufreq_gx_cpu_init,
0441 .name = "gx-suspmod",
0442 };
0443
0444 static int __init cpufreq_gx_init(void)
0445 {
0446 int ret;
0447 struct gxfreq_params *params;
0448 struct pci_dev *gx_pci;
0449
0450
0451 gx_pci = gx_detect_chipset();
0452 if (gx_pci == NULL)
0453 return -ENODEV;
0454
0455
0456 if (max_duration > 0xff)
0457 max_duration = 0xff;
0458
0459 pr_debug("geode suspend modulation available.\n");
0460
0461 params = kzalloc(sizeof(*params), GFP_KERNEL);
0462 if (params == NULL)
0463 return -ENOMEM;
0464
0465 params->cs55x0 = gx_pci;
0466 gx_params = params;
0467
0468
0469 pci_read_config_byte(params->cs55x0, PCI_SUSCFG, &(params->pci_suscfg));
0470 pci_read_config_byte(params->cs55x0, PCI_PMER1, &(params->pci_pmer1));
0471 pci_read_config_byte(params->cs55x0, PCI_PMER2, &(params->pci_pmer2));
0472 pci_read_config_byte(params->cs55x0, PCI_MODON, &(params->on_duration));
0473 pci_read_config_byte(params->cs55x0, PCI_MODOFF,
0474 &(params->off_duration));
0475
0476 ret = cpufreq_register_driver(&gx_suspmod_driver);
0477 if (ret) {
0478 kfree(params);
0479 return ret;
0480 }
0481
0482 return 0;
0483 }
0484
0485 static void __exit cpufreq_gx_exit(void)
0486 {
0487 cpufreq_unregister_driver(&gx_suspmod_driver);
0488 pci_dev_put(gx_params->cs55x0);
0489 kfree(gx_params);
0490 }
0491
0492 MODULE_AUTHOR("Hiroshi Miura <miura@da-cha.org>");
0493 MODULE_DESCRIPTION("Cpufreq driver for Cyrix MediaGX and NatSemi Geode");
0494 MODULE_LICENSE("GPL");
0495
0496 module_init(cpufreq_gx_init);
0497 module_exit(cpufreq_gx_exit);
0498