1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75#include <linux/config.h>
76#include <linux/module.h>
77#include <linux/slab.h>
78#include <linux/pci.h>
79#include <linux/delay.h>
80#include <linux/pm.h>
81#include <linux/init.h>
82
83#include "amd76x_pm.h"
84
85#define VERSION "20020730"
86
87
88
89
90
91
92extern void default_idle(void);
93static void amd76x_smp_idle(void);
94static int amd76x_pm_main(void);
95static int __devinit amd_nb_init(struct pci_dev *pdev,
96 const struct pci_device_id *ent);
97static void amd_nb_remove(struct pci_dev *pdev);
98static int __devinit amd_sb_init(struct pci_dev *pdev,
99 const struct pci_device_id *ent);
100static void amd_sb_remove(struct pci_dev *pdev);
101
102
103static struct pci_dev *pdev_nb;
104static struct pci_dev *pdev_sb;
105
106struct PM_cfg {
107 unsigned int status_reg;
108 unsigned int C2_reg;
109 unsigned int C3_reg;
110 unsigned int NTH_reg;
111 unsigned int slp_reg;
112 unsigned int resume_reg;
113 void (*orig_idle) (void);
114 void (*curr_idle) (void);
115 unsigned long C2_cnt, C3_cnt;
116 int last_pr;
117};
118static struct PM_cfg amd76x_pm_cfg;
119
120struct cpu_idle_state {
121 int idle;
122 int count;
123};
124static struct cpu_idle_state prs[2];
125
126static struct pci_device_id amd_nb_tbl[] __devinitdata = {
127 {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, PCI_ANY_ID, PCI_ANY_ID,},
128 {0,}
129};
130
131static struct pci_device_id amd_sb_tbl[] __devinitdata = {
132 {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413, PCI_ANY_ID, PCI_ANY_ID,},
133 {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7443, PCI_ANY_ID, PCI_ANY_ID,},
134 {0,}
135};
136
137static struct pci_driver amd_nb_driver = {
138 name:"amd76x_pm-nb",
139 id_table:amd_nb_tbl,
140 probe:amd_nb_init,
141 remove:__devexit_p(amd_nb_remove),
142};
143
144static struct pci_driver amd_sb_driver = {
145 name:"amd76x_pm-sb",
146 id_table:amd_sb_tbl,
147 probe:amd_sb_init,
148 remove:__devexit_p(amd_sb_remove),
149};
150
151
152static int __devinit
153amd_nb_init(struct pci_dev *pdev, const struct pci_device_id *ent)
154{
155 pdev_nb = pdev;
156 printk(KERN_INFO "amd76x_pm: Initializing northbridge %s\n",
157 pdev_nb->name);
158
159 return 0;
160}
161
162
163static void __devexit
164amd_nb_remove(struct pci_dev *pdev)
165{
166}
167
168
169static int __devinit
170amd_sb_init(struct pci_dev *pdev, const struct pci_device_id *ent)
171{
172 pdev_sb = pdev;
173 printk(KERN_INFO "amd76x_pm: Initializing southbridge %s\n",
174 pdev_sb->name);
175
176 return 0;
177}
178
179
180static void __devexit
181amd_sb_remove(struct pci_dev *pdev)
182{
183}
184
185
186
187
188
189static int
190config_amd762(int enable)
191{
192 unsigned int regdword;
193
194
195 pci_read_config_dword(pdev_nb, 0x60, ®dword);
196 regdword |= (1 << 17);
197 pci_write_config_dword(pdev_nb, 0x60, regdword);
198
199
200 pci_read_config_dword(pdev_nb, 0x68, ®dword);
201 regdword |= (1 << 17);
202 pci_write_config_dword(pdev_nb, 0x68, regdword);
203
204
205 pci_read_config_dword(pdev_nb, 0x58, ®dword);
206 regdword &= ~(1 << 19);
207 pci_write_config_dword(pdev_nb, 0x58, regdword);
208
209
210 pci_read_config_dword(pdev_nb, 0x70, ®dword);
211 regdword |= (1 << 18);
212 pci_write_config_dword(pdev_nb, 0x70, regdword);
213
214 return 0;
215}
216
217
218
219
220
221static void
222amd76x_get_PM(void)
223{
224 unsigned int regdword;
225
226
227 pci_read_config_dword(pdev_sb, 0x58, ®dword);
228 regdword &= 0xff80;
229 amd76x_pm_cfg.status_reg = (regdword + 0x00);
230 amd76x_pm_cfg.slp_reg = (regdword + 0x04);
231 amd76x_pm_cfg.NTH_reg = (regdword + 0x10);
232 amd76x_pm_cfg.C2_reg = (regdword + 0x14);
233 amd76x_pm_cfg.C3_reg = (regdword + 0x15);
234 amd76x_pm_cfg.resume_reg = (regdword + 0x16);
235}
236
237
238
239
240
241static int
242config_PMIO_amd76x(int is_766, int enable)
243{
244 unsigned char regbyte;
245
246
247
248
249 pci_read_config_byte(pdev_sb, 0x41, ®byte);
250 if(enable) {
251 regbyte |= ((0 << 0) | (is_766?1:0 << 1) | (1 << 7));
252 }
253 else {
254 regbyte |= (0 << 7);
255 }
256 pci_write_config_byte(pdev_sb, 0x41, regbyte);
257
258 return 0;
259}
260
261
262
263
264static void
265config_amd766_C2(int enable)
266{
267 unsigned int regdword;
268
269
270 pci_read_config_dword(pdev_sb, 0x50, ®dword);
271 if(enable) {
272 regdword &= ~((DCSTOP_EN | CPUSTP_EN | PCISTP_EN | SUSPND_EN |
273 CPURST_EN) << C2_REGS);
274 regdword |= (STPCLK_EN
275 | CPUSLP_EN)
276 << C2_REGS;
277 }
278 else
279 regdword &= ~((STPCLK_EN | CPUSLP_EN) << C2_REGS);
280 pci_write_config_dword(pdev_sb, 0x50, regdword);
281}
282
283
284#ifdef AMD76X_C3
285
286
287
288static void
289config_amd766_C3(int enable)
290{
291 unsigned int regdword;
292
293
294 pci_read_config_dword(pdev_sb, 0x50, ®dword);
295 if(enable) {
296 regdword &= ~((DCSTOP_EN | PCISTP_EN | SUSPND_EN | CPURST_EN)
297 << C3_REGS);
298 regdword |= (STPCLK_EN
299 | CPUSLP_EN
300 | CPUSTP_EN)
301 << C3_REGS;
302 }
303 else
304 regdword &= ~((STPCLK_EN | CPUSLP_EN | CPUSTP_EN) << C3_REGS);
305 pci_write_config_dword(pdev_sb, 0x50, regdword);
306}
307#endif
308
309
310#ifdef AMD76X_POS
311static void
312config_amd766_POS(int enable)
313{
314 unsigned int regdword;
315
316
317 pci_read_config_dword(pdev_sb, 0x50, ®dword);
318 if(enable) {
319 regdword &= ~((ZZ_CACHE_EN | CPURST_EN) << POS_REGS);
320 regdword |= ((DCSTOP_EN | STPCLK_EN | CPUSTP_EN | PCISTP_EN |
321 CPUSLP_EN | SUSPND_EN) << POS_REGS);
322 }
323 else
324 regdword ^= (0xff << POS_REGS);
325 pci_write_config_dword(pdev_sb, 0x50, regdword);
326}
327#endif
328
329
330
331
332
333static int
334config_amd766(int enable)
335{
336 amd76x_get_PM();
337 config_PMIO_amd76x(1, 1);
338
339 config_amd766_C2(enable);
340#ifdef AMD76X_C3
341 config_amd766_C3(enable);
342#endif
343#ifdef AMD76X_POS
344 config_amd766_POS(enable);
345#endif
346
347 return 0;
348}
349
350
351
352
353
354static void
355config_amd768_C2(int enable)
356{
357 unsigned char regbyte;
358
359
360 pci_read_config_byte(pdev_sb, 0x4F, ®byte);
361 if(enable)
362 regbyte |= C2EN;
363 else
364 regbyte ^= C2EN;
365 pci_write_config_byte(pdev_sb, 0x4F, regbyte);
366}
367
368
369#ifdef AMD76X_C3
370
371
372
373
374
375
376static void
377config_amd768_C3(int enable)
378{
379 unsigned char regbyte;
380
381
382 pci_read_config_byte(pdev_sb, 0x4F, ®byte);
383 if(enable)
384 regbyte |= (C3EN );
385 else
386 regbyte ^= C3EN;
387 pci_write_config_byte(pdev_sb, 0x4F, regbyte);
388}
389#endif
390
391
392#ifdef AMD76X_POS
393
394
395
396
397static void
398config_amd768_POS(int enable)
399{
400 unsigned int regdword;
401
402
403 pci_read_config_dword(pdev_sb, 0x50, ®dword);
404 if(enable)
405 regdword |= (POSEN | CSTP | PSTP | ASTP | DCSTP | CSLP | SUSP);
406 else
407 regdword ^= POSEN;
408 pci_write_config_dword(pdev_sb, 0x50, regdword);
409}
410#endif
411
412
413#ifdef AMD76X_NTH
414
415
416
417
418
419static void
420config_amd768_NTH(int enable, int ntper, int thminen)
421{
422 unsigned char regbyte;
423
424
425 pci_read_config_byte(pdev_sb, 0x40, ®byte);
426
427 regbyte |= (NTPER(ntper) | THMINEN(thminen));
428 pci_write_config_byte(pdev_sb, 0x40, regbyte);
429}
430#endif
431
432
433
434
435
436
437static int
438config_amd768(int enable)
439{
440 amd76x_get_PM();
441 config_PMIO_amd76x(0, 1);
442
443 config_amd768_C2(enable);
444#ifdef AMD76X_C3
445 config_amd768_C3(enable);
446#endif
447#ifdef AMD76X_POS
448 config_amd768_POS(enable);
449#endif
450#ifdef AMD76X_NTH
451 config_amd768_NTH(enable, 1, 2);
452#endif
453
454 return 0;
455}
456
457
458#ifdef AMD76X_NTH
459
460
461
462static void
463activate_amd76x_NTH(int enable, int ratio)
464{
465 unsigned int regdword;
466
467
468 regdword=inl(amd76x_pm_cfg.NTH_reg);
469 if(enable)
470 regdword |= (NTH_EN | NTH_RATIO(ratio));
471 else
472 regdword ^= NTH_EN;
473 outl(regdword, amd76x_pm_cfg.NTH_reg);
474}
475#endif
476
477#ifdef AMD76X_POS
478
479
480
481static void
482activate_amd76x_SLP(int type)
483{
484 unsigned short regshort;
485
486
487 regshort=inw(amd76x_pm_cfg.slp_reg);
488 regshort |= (SLP_EN | SLP_TYP(type)) ;
489 outw(regshort, amd76x_pm_cfg.slp_reg);
490}
491
492
493
494
495static void
496activate_amd76x_POS(void)
497{
498 activate_amd76x_SLP(1);
499}
500#endif
501
502
503#if 0
504
505
506
507void
508amd76x_up_idle(void)
509{
510
511}
512#endif
513
514
515
516
517
518
519
520static void
521amd76x_smp_idle(void)
522{
523
524
525
526
527
528 if (prs[0].idle && prs[1].idle && amd76x_pm_cfg.last_pr == smp_processor_id()) {
529 prs[0].idle = 0;
530 prs[1].idle = 0;
531
532
533 return;
534 }
535
536 prs[smp_processor_id()].count++;
537
538
539 if (prs[smp_processor_id()].count >= LAZY_IDLE_DELAY) {
540
541
542 prs[smp_processor_id()].idle =
543 (prs[smp_processor_id()].idle ? 2 : 1);
544
545
546 if ((prs[0].idle==1) && (prs[1].idle==1)) {
547 amd76x_pm_cfg.C2_cnt++;
548 inb(amd76x_pm_cfg.C2_reg);
549 }
550 #ifdef AMD76X_C3
551
552
553
554
555
556 else if ((prs[0].idle==2) && (prs[1].idle==2)) {
557 amd76x_pm_cfg.C3_cnt++;
558 inb(amd76x_pm_cfg.C3_reg);
559 }
560 #endif
561
562 prs[smp_processor_id()].count = 0;
563
564 }
565 amd76x_pm_cfg.last_pr = smp_processor_id();
566}
567
568
569
570
571
572static int
573amd76x_pm_main(void)
574{
575 int found;
576
577
578 found = pci_register_driver(&amd_nb_driver);
579 if (found <= 0) {
580 printk(KERN_ERR "amd76x_pm: Could not find northbridge\n");
581 pci_unregister_driver(&amd_nb_driver);
582 return 1;
583 }
584
585
586 found = pci_register_driver(&amd_sb_driver);
587 if (found <= 0) {
588 printk(KERN_ERR "amd76x_pm: Could not find southbridge\n");
589 pci_unregister_driver(&amd_sb_driver);
590 pci_unregister_driver(&amd_nb_driver);
591 return 1;
592 }
593
594
595 switch (pdev_sb->device) {
596 case PCI_DEVICE_ID_AMD_VIPER_7413:
597 config_amd766(1);
598 break;
599 case PCI_DEVICE_ID_AMD_VIPER_7443:
600 config_amd768(1);
601 break;
602 default:
603 printk(KERN_ERR "amd76x_pm: No southbridge to initialize\n");
604 break;
605 }
606
607
608 switch (pdev_nb->device) {
609 case PCI_DEVICE_ID_AMD_FE_GATE_700C:
610 config_amd762(1);
611#ifndef AMD76X_NTH
612 amd76x_pm_cfg.curr_idle = amd76x_smp_idle;
613#endif
614 break;
615 default:
616 printk(KERN_ERR "amd76x_pm: No northbridge to initialize\n");
617 break;
618 }
619
620#ifndef AMD76X_NTH
621 if (!amd76x_pm_cfg.curr_idle) {
622 printk(KERN_ERR "amd76x_pm: Idle function not changed\n");
623 pci_unregister_driver(&amd_nb_driver);
624 pci_unregister_driver(&amd_sb_driver);
625 return 1;
626 }
627
628 amd76x_pm_cfg.orig_idle = pm_idle;
629 pm_idle = amd76x_pm_cfg.curr_idle;
630#endif
631
632#ifdef AMD76X_NTH
633
634 activate_amd76x_NTH(1, 1);
635#endif
636
637#ifdef AMD76X_POS
638
639 activate_amd76x_POS();
640#endif
641
642 return 0;
643}
644
645
646static int __init
647amd76x_pm_init(void)
648{
649 printk(KERN_INFO "amd76x_pm: Version %s\n", VERSION);
650 return amd76x_pm_main();
651}
652
653
654static void __exit
655amd76x_pm_cleanup(void)
656{
657#ifndef AMD76X_NTH
658 pm_idle = amd76x_pm_cfg.orig_idle;
659
660
661 printk(KERN_INFO "amd76x_pm: %lu C2 calls\n", amd76x_pm_cfg.C2_cnt);
662#ifdef AMD76X_C3
663 printk(KERN_INFO "amd76x_pm: %lu C3 calls\n", amd76x_pm_cfg.C3_cnt);
664#endif
665
666
667
668
669
670
671
672
673
674 schedule();
675 mdelay(1000);
676#endif
677
678#ifdef AMD76X_NTH
679
680 activate_amd76x_NTH(0, 0);
681#endif
682
683 pci_unregister_driver(&amd_nb_driver);
684 pci_unregister_driver(&amd_sb_driver);
685
686}
687
688
689MODULE_LICENSE("GPL");
690module_init(amd76x_pm_init);
691module_exit(amd76x_pm_cleanup);
692