amd76x_pm.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:16k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * ACPI sytle PM for SMP AMD-760MP(X) based systems.
  3.  * For use until the ACPI project catches up. :-)
  4.  *
  5.  * Copyright (C) 2002 Johnathan Hicks <thetech@folkwolf.net>
  6.  *
  7.  * History:
  8.  * 
  9.  *   20020702 - amd-smp-idle: Tony Lindgren <tony@atomide.com>
  10.  * Influenced by Vcool, and LVCool. Rewrote everything from scratch to
  11.  * use the PCI features in Linux, and to support SMP systems. Provides
  12.  * C2 idling on SMP AMD-760MP systems.
  13.  *
  14.  *   20020722: JH
  15.  *    I adapted Tony's code for the AMD-765/766 southbridge and adapted it
  16.  *    according to the AMD-768 data sheet to provide the same capability for
  17.  *    SMP AMD-760MPX systems. Posted to acpi-devel list.
  18.  *   
  19.  *   20020722: Alan Cox
  20.  *    Replaces non-functional amd76x_pm code in -ac tree.
  21.  *   
  22.  *   20020730: JH
  23.  *    Added ability to do normal throttling (the non-thermal kind), C3 idling
  24.  *    and Power On Suspend (S1 sleep). It would be very easy to tie swsusp
  25.  *    into activate_amd76x_SLP(). C3 idling doesn't happen yet; see my note
  26.  *    in amd76x_smp_idle(). I've noticed that when NTH and idling are both
  27.  *    enabled, my hardware locks and requires a hard reset, so I have
  28.  *    #ifndefed around the idle loop setting to prevent this. POS locks it up
  29.  *    too, both ought to be fixable. I've also noticed that idling and NTH
  30.  *    make some interference that is picked up by the onboard sound chip on
  31.  *    my ASUS A7M266-D motherboard.
  32.  *
  33.  *
  34.  * TODO: Thermal throttling (TTH).
  35.  *   /proc interface for normal throttling level.
  36.  *   /proc interface for POS.
  37.  *
  38.  *
  39.  *    <Notes from 20020722-ac revision>
  40.  *
  41.  * Processor idle mode module for AMD SMP 760MP(X) based systems
  42.  *
  43.  * Copyright (C) 2002 Tony Lindgren <tony@atomide.com>
  44.  *                    Johnathan Hicks (768 support)
  45.  *
  46.  * Using this module saves about 70 - 90W of energy in the idle mode compared
  47.  * to the default idle mode. Waking up from the idle mode is fast to keep the
  48.  * system response time good. Currently no CPU load calculation is done, the
  49.  * system exits the idle mode if the idle function runs twice on the same
  50.  * processor in a row. This only works on SMP systems, but maybe the idle mode
  51.  * enabling can be integrated to ACPI to provide C2 mode at some point.
  52.  *
  53.  * NOTE: Currently there's a bug somewhere where the reading the
  54.  *       P_LVL2 for the first time causes the system to sleep instead of 
  55.  *       idling. This means that you need to hit the power button once to
  56.  *       wake the system after loading the module for the first time after
  57.  *       reboot. After that the system idles as supposed.
  58.  *
  59.  *
  60.  * Influenced by Vcool, and LVCool. Rewrote everything from scratch to
  61.  * use the PCI features in Linux, and to support SMP systems.
  62.  * 
  63.  * Currently only tested on a TYAN S2460 (760MP) system (Tony) and an
  64.  * ASUS A7M266-D (760MPX) system (Johnathan). Adding support for other Athlon
  65.  * SMP or single processor systems should be easy if desired.
  66.  *
  67.  * This software is licensed under GNU General Public License Version 2 
  68.  * as specified in file COPYING in the Linux kernel source tree main 
  69.  * directory.
  70.  * 
  71.  *   </Notes from 20020722-ac revision>
  72.  */
  73. #include <linux/config.h>
  74. #include <linux/module.h>
  75. #include <linux/slab.h>
  76. #include <linux/pci.h>
  77. #include <linux/delay.h>
  78. #include <linux/pm.h>
  79. #include "amd76x_pm.h"
  80. #define VERSION "20020730"
  81. // #define AMD76X_C3  1
  82. // #define AMD76X_NTH 1
  83. // #define AMD76X_POS 1
  84. extern void default_idle(void);
  85. static void amd76x_smp_idle(void);
  86. static int amd76x_pm_main(void);
  87. static int __devinit amd_nb_init(struct pci_dev *pdev,
  88.  const struct pci_device_id *ent);
  89. static void amd_nb_remove(struct pci_dev *pdev);
  90. static int __devinit amd_sb_init(struct pci_dev *pdev,
  91.  const struct pci_device_id *ent);
  92. static void amd_sb_remove(struct pci_dev *pdev);
  93. static struct pci_dev *pdev_nb;
  94. static struct pci_dev *pdev_sb;
  95. struct PM_cfg {
  96. unsigned int status_reg;
  97. unsigned int C2_reg;
  98. unsigned int C3_reg;
  99. unsigned int NTH_reg;
  100. unsigned int slp_reg;
  101. unsigned int resume_reg;
  102. void (*orig_idle) (void);
  103. void (*curr_idle) (void);
  104. unsigned long C2_cnt, C3_cnt;
  105. int last_pr;
  106. };
  107. static struct PM_cfg amd76x_pm_cfg;
  108. struct cpu_idle_state {
  109. int idle;
  110. int count;
  111. };
  112. static struct cpu_idle_state prs[2];
  113. static struct pci_device_id amd_nb_tbl[] __devinitdata = {
  114. {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, PCI_ANY_ID, PCI_ANY_ID,},
  115. {0,}
  116. };
  117. static struct pci_device_id amd_sb_tbl[] __devinitdata = {
  118. {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413, PCI_ANY_ID, PCI_ANY_ID,},
  119. {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7443, PCI_ANY_ID, PCI_ANY_ID,},
  120. {0,}
  121. };
  122. static struct pci_driver amd_nb_driver = {
  123. name:"amd76x_pm-nb",
  124. id_table:amd_nb_tbl,
  125. probe:amd_nb_init,
  126. remove:__devexit_p(amd_nb_remove),
  127. };
  128. static struct pci_driver amd_sb_driver = {
  129. name:"amd76x_pm-sb",
  130. id_table:amd_sb_tbl,
  131. probe:amd_sb_init,
  132. remove:__devexit_p(amd_sb_remove),
  133. };
  134. static int __devinit
  135. amd_nb_init(struct pci_dev *pdev, const struct pci_device_id *ent)
  136. {
  137. pdev_nb = pdev;
  138. printk(KERN_INFO "amd76x_pm: Initializing northbridge %sn",
  139.        pdev_nb->name);
  140. return 0;
  141. }
  142. static void __devexit
  143. amd_nb_remove(struct pci_dev *pdev)
  144. {
  145. }
  146. static int __devinit
  147. amd_sb_init(struct pci_dev *pdev, const struct pci_device_id *ent)
  148. {
  149. pdev_sb = pdev;
  150. printk(KERN_INFO "amd76x_pm: Initializing southbridge %sn",
  151.        pdev_sb->name);
  152. return 0;
  153. }
  154. static void __devexit
  155. amd_sb_remove(struct pci_dev *pdev)
  156. {
  157. }
  158. /*
  159.  * Configures the AMD-762 northbridge to support PM calls
  160.  */
  161. static int
  162. config_amd762(int enable)
  163. {
  164. unsigned int regdword;
  165. /* Enable STPGNT in BIU Status/Control for cpu0 */
  166. pci_read_config_dword(pdev_nb, 0x60, &regdword);
  167. regdword |= (1 << 17);
  168. pci_write_config_dword(pdev_nb, 0x60, regdword);
  169. /* Enable STPGNT in BIU Status/Control for cpu1 */
  170. pci_read_config_dword(pdev_nb, 0x68, &regdword);
  171. regdword |= (1 << 17);
  172. pci_write_config_dword(pdev_nb, 0x68, regdword);
  173. /* DRAM refresh enable */
  174. pci_read_config_dword(pdev_nb, 0x58, &regdword);
  175. regdword &= ~(1 << 19);
  176. pci_write_config_dword(pdev_nb, 0x58, regdword);
  177. /* Self refresh enable */
  178. pci_read_config_dword(pdev_nb, 0x70, &regdword);
  179. regdword |= (1 << 18);
  180. pci_write_config_dword(pdev_nb, 0x70, regdword);
  181. return 0;
  182. }
  183. /*
  184.  * Get the base PMIO address and set the pm registers in amd76x_pm_cfg.
  185.  */
  186. static void
  187. amd76x_get_PM(void)
  188. {
  189. unsigned int regdword;
  190. /* Get the address for pm status, P_LVL2, etc */
  191. pci_read_config_dword(pdev_sb, 0x58, &regdword);
  192. regdword &= 0xff80;
  193. amd76x_pm_cfg.status_reg = (regdword + 0x00);
  194. amd76x_pm_cfg.slp_reg =    (regdword + 0x04);
  195. amd76x_pm_cfg.NTH_reg =    (regdword + 0x10);
  196. amd76x_pm_cfg.C2_reg =     (regdword + 0x14);
  197. amd76x_pm_cfg.C3_reg =     (regdword + 0x15);
  198. amd76x_pm_cfg.resume_reg = (regdword + 0x16); /* N/A for 768 */
  199. }
  200. /*
  201.  * En/Disable PMIO and configure W4SG & STPGNT.
  202.  */
  203. static int
  204. config_PMIO_amd76x(int is_766, int enable)
  205. {
  206. unsigned char regbyte;
  207. /* Clear W4SG, and set PMIOEN, if using a 765/766 set STPGNT as well.
  208.  * AMD-766: C3A41; page 59 in AMD-766 doc
  209.  * AMD-768: DevB:3x41C; page 94 in AMD-768 doc */
  210. pci_read_config_byte(pdev_sb, 0x41, &regbyte);
  211. if(enable) {
  212. regbyte |= ((0 << 0) | (is_766?1:0 << 1) | (1 << 7));
  213. }
  214. else {
  215. regbyte |= (0 << 7);
  216. }
  217. pci_write_config_byte(pdev_sb, 0x41, regbyte);
  218. return 0;
  219. }
  220. /*
  221.  * C2 idle support for AMD-766.
  222.  */
  223. static void
  224. config_amd766_C2(int enable)
  225. {
  226. unsigned int regdword;
  227. /* Set C2 options in C3A50, page 63 in AMD-766 doc */
  228. pci_read_config_dword(pdev_sb, 0x50, &regdword);
  229. if(enable) {
  230. regdword &= ~((DCSTOP_EN | CPUSTP_EN | PCISTP_EN | SUSPND_EN |
  231. CPURST_EN) << C2_REGS);
  232. regdword |= (STPCLK_EN /* ~ 20 Watt savings max */
  233.  |  CPUSLP_EN) /* Additional ~ 70 Watts max! */
  234.  << C2_REGS;
  235. }
  236. else
  237. regdword &= ~((STPCLK_EN | CPUSLP_EN) << C2_REGS);
  238. pci_write_config_dword(pdev_sb, 0x50, regdword);
  239. }
  240. #ifdef AMD76X_C3
  241. /*
  242.  * Untested C3 idle support for AMD-766.
  243.  */
  244. static void
  245. config_amd766_C3(int enable)
  246. {
  247. unsigned int regdword;
  248. /* Set C3 options in C3A50, page 63 in AMD-766 doc */
  249. pci_read_config_dword(pdev_sb, 0x50, &regdword);
  250. if(enable) {
  251. regdword &= ~((DCSTOP_EN | PCISTP_EN | SUSPND_EN | CPURST_EN)
  252. << C3_REGS);
  253. regdword |= (STPCLK_EN /* ~ 20 Watt savings max */
  254.  |  CPUSLP_EN /* Additional ~ 70 Watts max! */
  255.  |  CPUSTP_EN) /* yet more savings! */
  256.  << C3_REGS;
  257. }
  258. else
  259. regdword &= ~((STPCLK_EN | CPUSLP_EN | CPUSTP_EN) << C3_REGS);
  260. pci_write_config_dword(pdev_sb, 0x50, regdword);
  261. }
  262. #endif
  263. #ifdef AMD76X_POS
  264. static void
  265. config_amd766_POS(int enable)
  266. {
  267. unsigned int regdword;
  268. /* Set C3 options in C3A50, page 63 in AMD-766 doc */
  269. pci_read_config_dword(pdev_sb, 0x50, &regdword);
  270. if(enable) {
  271. regdword &= ~((ZZ_CACHE_EN | CPURST_EN) << POS_REGS);
  272. regdword |= ((DCSTOP_EN | STPCLK_EN | CPUSTP_EN | PCISTP_EN |
  273. CPUSLP_EN | SUSPND_EN) << POS_REGS);
  274. }
  275. else
  276. regdword ^= (0xff << POS_REGS);
  277. pci_write_config_dword(pdev_sb, 0x50, regdword);
  278. }
  279. #endif
  280. /*
  281.  * Configures the 765 & 766 southbridges.
  282.  */
  283. static int
  284. config_amd766(int enable)
  285. {
  286. amd76x_get_PM();
  287. config_PMIO_amd76x(1, 1);
  288. config_amd766_C2(enable);
  289. #ifdef AMD76X_C3
  290. config_amd766_C3(enable);
  291. #endif
  292. #ifdef AMD76X_POS
  293. config_amd766_POS(enable);
  294. #endif
  295. return 0;
  296. }
  297. /*
  298.  * C2 idling support for AMD-768.
  299.  */
  300. static void
  301. config_amd768_C2(int enable)
  302. {
  303. unsigned char regbyte;
  304. /* Set C2 options in DevB:3x4F, page 100 in AMD-768 doc */
  305. pci_read_config_byte(pdev_sb, 0x4F, &regbyte);
  306. if(enable)
  307. regbyte |= C2EN;
  308. else
  309. regbyte ^= C2EN;
  310. pci_write_config_byte(pdev_sb, 0x4F, regbyte);
  311. }
  312. #ifdef AMD76X_C3
  313. /*
  314.  * C3 idle support for AMD-768. The idle loop would need some extra
  315.  * handling for C3, but it would make more sense for ACPI to handle CX level
  316.  * transitions like it is supposed to. Unfortunately ACPI doesn't do CX
  317.  * levels on SMP systems yet.
  318.  */
  319. static void
  320. config_amd768_C3(int enable)
  321. {
  322. unsigned char regbyte;
  323. /* Set C3 options in DevB:3x4F, page 100 in AMD-768 doc */
  324. pci_read_config_byte(pdev_sb, 0x4F, &regbyte);
  325. if(enable)
  326. regbyte |= (C3EN /* | ZZ_C3EN | CSLP_C3EN | CSTP_C3EN */);
  327. else
  328. regbyte ^= C3EN;
  329. pci_write_config_byte(pdev_sb, 0x4F, regbyte);
  330. }
  331. #endif
  332. #ifdef AMD76X_POS
  333. /*
  334.  * Untested Power On Suspend support for AMD-768. This should also be handled
  335.  * by ACPI.
  336.  */
  337. static void
  338. config_amd768_POS(int enable)
  339. {
  340. unsigned int regdword;
  341. /* Set POS options in DevB:3x50, page 101 in AMD-768 doc */
  342. pci_read_config_dword(pdev_sb, 0x50, &regdword);
  343. if(enable) 
  344. regdword |= (POSEN | CSTP | PSTP | ASTP | DCSTP | CSLP | SUSP);
  345. else
  346. regdword ^= POSEN;
  347. pci_write_config_dword(pdev_sb, 0x50, regdword);
  348. }
  349. #endif
  350. #ifdef AMD76X_NTH
  351. /*
  352.  * Normal Throttling support for AMD-768. There are several settings
  353.  * that can be set depending on how long you want some of the delays to be.
  354.  * I'm not sure if this is even neccessary at all as the 766 doesn't need this.
  355.  */
  356. static void
  357. config_amd768_NTH(int enable, int ntper, int thminen)
  358. {
  359. unsigned char regbyte;
  360. /* DevB:3x40, pg 93 of 768 doc */
  361. pci_read_config_byte(pdev_sb, 0x40, &regbyte);
  362. /* Is it neccessary to use THMINEN at ANY time? */
  363. regbyte |= (NTPER(ntper) | THMINEN(thminen));
  364. pci_write_config_byte(pdev_sb, 0x40, regbyte);
  365. }
  366. #endif
  367. /*
  368.  * Configures the 768 southbridge to support idle calls, and gets
  369.  * the processor idle call register location.
  370.  */
  371. static int
  372. config_amd768(int enable)
  373. {
  374. amd76x_get_PM();
  375. config_PMIO_amd76x(0, 1);
  376. config_amd768_C2(enable);
  377. #ifdef AMD76X_C3
  378. config_amd768_C3(enable);
  379. #endif
  380. #ifdef AMD76X_POS
  381. config_amd768_POS(enable);
  382. #endif
  383. #ifdef AMD76X_NTH
  384. config_amd768_NTH(enable, 1, 2);
  385. #endif
  386. return 0;
  387. }
  388. #ifdef AMD76X_NTH
  389. /*
  390.  * Activate normal throttling via its ACPI register (P_CNT).
  391.  */
  392. static void
  393. activate_amd76x_NTH(int enable, int ratio)
  394. {
  395. unsigned int regdword;
  396. /* PM10, pg 110 of 768 doc, pg 70 of 766 doc */
  397. regdword=inl(amd76x_pm_cfg.NTH_reg);
  398. if(enable)
  399. regdword |= (NTH_EN | NTH_RATIO(ratio));
  400. else
  401. regdword ^= NTH_EN;
  402. outl(regdword, amd76x_pm_cfg.NTH_reg);
  403. }
  404. #endif
  405. /*
  406.  * Activate sleep state via its ACPI register (PM1_CNT).
  407.  */
  408. static void
  409. activate_amd76x_SLP(int type)
  410. {
  411. unsigned short regshort;
  412. /* PM04, pg 109 of 768 doc, pg 69 of 766 doc */
  413. regshort=inw(amd76x_pm_cfg.slp_reg);
  414. regshort |= (SLP_EN | SLP_TYP(type)) ;
  415. outw(regshort, amd76x_pm_cfg.slp_reg);
  416. }
  417. #ifdef AMD76X_POS
  418. /*
  419.  * Wrapper function to activate POS sleep state.
  420.  */
  421. static void
  422. activate_amd76x_POS(void)
  423. {
  424. activate_amd76x_SLP(1);
  425. }
  426. #endif
  427. #if 0
  428. /*
  429.  * Idle loop for single processor systems
  430.  */
  431. void
  432. amd76x_up_idle(void)
  433. {
  434. // FIXME: Optionally add non-smp idle loop here
  435. }
  436. #endif
  437. /*
  438.  * Idle loop for SMP systems, supports currently only 2 processors.
  439.  *
  440.  * Note; for 2.5 folks - not pre-empt safe
  441.  */
  442. static void
  443. amd76x_smp_idle(void)
  444. {
  445. /*
  446.  * Exit idle mode immediately if the CPU does not change.
  447.  * Usually that means that we have some load on another CPU.
  448.  */
  449. if (prs[0].idle && prs[1].idle && amd76x_pm_cfg.last_pr == smp_processor_id()) {
  450. prs[0].idle = 0;
  451. prs[1].idle = 0;
  452. /* This looks redundent as it was just checked in the if() */
  453. /* amd76x_pm_cfg.last_pr = smp_processor_id(); */
  454. return;
  455. }
  456. prs[smp_processor_id()].count++;
  457. /* Don't start the idle mode immediately */
  458. if (prs[smp_processor_id()].count >= LAZY_IDLE_DELAY) {
  459. /* Put the current processor into idle mode */
  460. prs[smp_processor_id()].idle =
  461. (prs[smp_processor_id()].idle ? 2 : 1);
  462. /* Only idle if both processors are idle */
  463. if ((prs[0].idle==1) && (prs[1].idle==1)) {
  464. amd76x_pm_cfg.C2_cnt++;
  465. inb(amd76x_pm_cfg.C2_reg);
  466. }
  467. #ifdef AMD76X_C3
  468. /*
  469.  * JH: I've not been able to get into here. Could this have
  470.  * something to do with the way the kernel handles the idle
  471.  * loop, or and error that I've made?
  472.  */
  473. else if ((prs[0].idle==2) && (prs[1].idle==2)) {
  474. amd76x_pm_cfg.C3_cnt++;
  475. inb(amd76x_pm_cfg.C3_reg);
  476. }
  477. #endif
  478. prs[smp_processor_id()].count = 0;
  479. }
  480. amd76x_pm_cfg.last_pr = smp_processor_id();
  481. }
  482. /*
  483.  * Finds and initializes the bridges, and then sets the idle function
  484.  */
  485. static int
  486. amd76x_pm_main(void)
  487. {
  488. int found;
  489. /* Find northbridge */
  490. found = pci_module_init(&amd_nb_driver);
  491. if (found < 0) {
  492. printk(KERN_ERR "amd76x_pm: Could not find northbridgen");
  493. return 1;
  494. }
  495. /* Find southbridge */
  496. found = pci_module_init(&amd_sb_driver);
  497. if (found < 0) {
  498. printk(KERN_ERR "amd76x_pm: Could not find southbridgen");
  499. pci_unregister_driver(&amd_nb_driver);
  500. return 1;
  501. }
  502. /* Init southbridge */
  503. switch (pdev_sb->device) {
  504. case PCI_DEVICE_ID_AMD_VIPER_7413: /* AMD-765 or 766 */
  505. config_amd766(1);
  506. break;
  507. case PCI_DEVICE_ID_AMD_VIPER_7443: /* AMD-768 */
  508. config_amd768(1);
  509. break;
  510. default:
  511. printk(KERN_ERR "amd76x_pm: No southbridge to initializen");
  512. break;
  513. }
  514. /* Init northbridge and queue the new idle function */
  515. switch (pdev_nb->device) {
  516. case PCI_DEVICE_ID_AMD_FE_GATE_700C: /* AMD-762 */
  517. config_amd762(1);
  518. #ifndef AMD76X_NTH
  519. amd76x_pm_cfg.curr_idle = amd76x_smp_idle;
  520. #endif
  521. break;
  522. default:
  523. printk(KERN_ERR "amd76x_pm: No northbridge to initializen");
  524. break;
  525. }
  526. #ifndef AMD76X_NTH
  527. if (!amd76x_pm_cfg.curr_idle) {
  528. printk(KERN_ERR "amd76x_pm: Idle function not changedn");
  529. return 1;
  530. }
  531. amd76x_pm_cfg.orig_idle = pm_idle;
  532. pm_idle = amd76x_pm_cfg.curr_idle;
  533. #endif
  534. #ifdef AMD76X_NTH
  535. /* Turn NTH on with maxium throttling for testing. */
  536. activate_amd76x_NTH(1, 1);
  537. #endif
  538. #ifdef AMD76X_POS
  539. /* Testing here only. */
  540. activate_amd76x_POS();
  541. #endif
  542. return 0;
  543. }
  544. static int __init
  545. amd76x_pm_init(void)
  546. {
  547. printk(KERN_INFO "amd76x_pm: Version %sn", VERSION);
  548. return amd76x_pm_main();
  549. }
  550. static void __exit
  551. amd76x_pm_cleanup(void)
  552. {
  553. #ifndef AMD76X_NTH
  554. pm_idle = amd76x_pm_cfg.orig_idle;
  555. /* This isn't really needed. */
  556. printk(KERN_INFO "amd76x_pm: %lu C2 callsn", amd76x_pm_cfg.C2_cnt);
  557. #ifdef AMD76X_C3
  558. printk(KERN_INFO "amd76x_pm: %lu C3 callsn", amd76x_pm_cfg.C3_cnt);
  559. #endif
  560. /* 
  561.  * FIXME: We want to wait until all CPUs have set the new
  562.  * idle function, otherwise we will oops. This may not be
  563.  * the right way to do it, but seems to work.
  564.  *
  565.  * - Best answer is going to be to ban unload, but when its debugged
  566.  *   --- Alan
  567.  */
  568. schedule();
  569. mdelay(1000);
  570. #endif
  571. #ifdef AMD76X_NTH
  572. /* Turn NTH off*/
  573. activate_amd76x_NTH(0, 0);
  574. #endif
  575. pci_unregister_driver(&amd_nb_driver);
  576. pci_unregister_driver(&amd_sb_driver);
  577. }
  578. MODULE_LICENSE("GPL");
  579. module_init(amd76x_pm_init);
  580. module_exit(amd76x_pm_cleanup);