diff options
Diffstat (limited to 'drivers/macintosh')
-rw-r--r-- | drivers/macintosh/via-pmu.c | 172 |
1 files changed, 36 insertions, 136 deletions
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 6df3f3503e5b..0e233185ad14 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c | |||
@@ -202,6 +202,12 @@ static int proc_read_options(char *page, char **start, off_t off, | |||
202 | static int proc_write_options(struct file *file, const char __user *buffer, | 202 | static int proc_write_options(struct file *file, const char __user *buffer, |
203 | unsigned long count, void *data); | 203 | unsigned long count, void *data); |
204 | 204 | ||
205 | #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32) | ||
206 | static void powerbook_sleep_init_3400(void); | ||
207 | #else | ||
208 | #define powerbook_sleep_init_3400() do { } while (0) | ||
209 | #endif | ||
210 | |||
205 | #ifdef CONFIG_ADB | 211 | #ifdef CONFIG_ADB |
206 | struct adb_driver via_pmu_driver = { | 212 | struct adb_driver via_pmu_driver = { |
207 | "PMU", | 213 | "PMU", |
@@ -449,6 +455,10 @@ static int __init via_pmu_start(void) | |||
449 | pmu_poll(); | 455 | pmu_poll(); |
450 | } while (pmu_state != idle); | 456 | } while (pmu_state != idle); |
451 | 457 | ||
458 | /* Do allocations and ioremaps that will be needed for sleep */ | ||
459 | if (pmu_kind == PMU_OHARE_BASED) | ||
460 | powerbook_sleep_init_3400(); | ||
461 | |||
452 | return 0; | 462 | return 0; |
453 | } | 463 | } |
454 | 464 | ||
@@ -1719,108 +1729,6 @@ pmu_present(void) | |||
1719 | } | 1729 | } |
1720 | 1730 | ||
1721 | #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32) | 1731 | #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32) |
1722 | /* | ||
1723 | * This struct is used to store config register values for | ||
1724 | * PCI devices which may get powered off when we sleep. | ||
1725 | */ | ||
1726 | static struct pci_save { | ||
1727 | u16 command; | ||
1728 | u16 cache_lat; | ||
1729 | u16 intr; | ||
1730 | u32 rom_address; | ||
1731 | } *pbook_pci_saves; | ||
1732 | static int pbook_npci_saves; | ||
1733 | |||
1734 | static void | ||
1735 | pbook_alloc_pci_save(void) | ||
1736 | { | ||
1737 | int npci; | ||
1738 | struct pci_dev *pd = NULL; | ||
1739 | |||
1740 | npci = 0; | ||
1741 | while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) { | ||
1742 | ++npci; | ||
1743 | } | ||
1744 | if (npci == 0) | ||
1745 | return; | ||
1746 | pbook_pci_saves = (struct pci_save *) | ||
1747 | kmalloc(npci * sizeof(struct pci_save), GFP_KERNEL); | ||
1748 | pbook_npci_saves = npci; | ||
1749 | } | ||
1750 | |||
1751 | static void | ||
1752 | pbook_free_pci_save(void) | ||
1753 | { | ||
1754 | if (pbook_pci_saves == NULL) | ||
1755 | return; | ||
1756 | kfree(pbook_pci_saves); | ||
1757 | pbook_pci_saves = NULL; | ||
1758 | pbook_npci_saves = 0; | ||
1759 | } | ||
1760 | |||
1761 | static void | ||
1762 | pbook_pci_save(void) | ||
1763 | { | ||
1764 | struct pci_save *ps = pbook_pci_saves; | ||
1765 | struct pci_dev *pd = NULL; | ||
1766 | int npci = pbook_npci_saves; | ||
1767 | |||
1768 | if (ps == NULL) | ||
1769 | return; | ||
1770 | |||
1771 | while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) { | ||
1772 | if (npci-- == 0) { | ||
1773 | pci_dev_put(pd); | ||
1774 | return; | ||
1775 | } | ||
1776 | pci_read_config_word(pd, PCI_COMMAND, &ps->command); | ||
1777 | pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat); | ||
1778 | pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr); | ||
1779 | pci_read_config_dword(pd, PCI_ROM_ADDRESS, &ps->rom_address); | ||
1780 | ++ps; | ||
1781 | } | ||
1782 | } | ||
1783 | |||
1784 | /* For this to work, we must take care of a few things: If gmac was enabled | ||
1785 | * during boot, it will be in the pci dev list. If it's disabled at this point | ||
1786 | * (and it will probably be), then you can't access it's config space. | ||
1787 | */ | ||
1788 | static void | ||
1789 | pbook_pci_restore(void) | ||
1790 | { | ||
1791 | u16 cmd; | ||
1792 | struct pci_save *ps = pbook_pci_saves - 1; | ||
1793 | struct pci_dev *pd = NULL; | ||
1794 | int npci = pbook_npci_saves; | ||
1795 | int j; | ||
1796 | |||
1797 | while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) { | ||
1798 | if (npci-- == 0) | ||
1799 | return; | ||
1800 | ps++; | ||
1801 | if (ps->command == 0) | ||
1802 | continue; | ||
1803 | pci_read_config_word(pd, PCI_COMMAND, &cmd); | ||
1804 | if ((ps->command & ~cmd) == 0) | ||
1805 | continue; | ||
1806 | switch (pd->hdr_type) { | ||
1807 | case PCI_HEADER_TYPE_NORMAL: | ||
1808 | for (j = 0; j < 6; ++j) | ||
1809 | pci_write_config_dword(pd, | ||
1810 | PCI_BASE_ADDRESS_0 + j*4, | ||
1811 | pd->resource[j].start); | ||
1812 | pci_write_config_dword(pd, PCI_ROM_ADDRESS, | ||
1813 | ps->rom_address); | ||
1814 | pci_write_config_word(pd, PCI_CACHE_LINE_SIZE, | ||
1815 | ps->cache_lat); | ||
1816 | pci_write_config_word(pd, PCI_INTERRUPT_LINE, | ||
1817 | ps->intr); | ||
1818 | pci_write_config_word(pd, PCI_COMMAND, ps->command); | ||
1819 | break; | ||
1820 | } | ||
1821 | } | ||
1822 | } | ||
1823 | |||
1824 | #ifdef DEBUG_SLEEP | 1732 | #ifdef DEBUG_SLEEP |
1825 | /* N.B. This doesn't work on the 3400 */ | 1733 | /* N.B. This doesn't work on the 3400 */ |
1826 | void | 1734 | void |
@@ -2200,37 +2108,34 @@ powerbook_sleep_Core99(void) | |||
2200 | #define PB3400_MEM_CTRL 0xf8000000 | 2108 | #define PB3400_MEM_CTRL 0xf8000000 |
2201 | #define PB3400_MEM_CTRL_SLEEP 0x70 | 2109 | #define PB3400_MEM_CTRL_SLEEP 0x70 |
2202 | 2110 | ||
2203 | static int | 2111 | static void __iomem *pb3400_mem_ctrl; |
2204 | powerbook_sleep_3400(void) | 2112 | |
2113 | static void powerbook_sleep_init_3400(void) | ||
2114 | { | ||
2115 | /* map in the memory controller registers */ | ||
2116 | pb3400_mem_ctrl = ioremap(PB3400_MEM_CTRL, 0x100); | ||
2117 | if (pb3400_mem_ctrl == NULL) | ||
2118 | printk(KERN_WARNING "ioremap failed: sleep won't be possible"); | ||
2119 | } | ||
2120 | |||
2121 | static int powerbook_sleep_3400(void) | ||
2205 | { | 2122 | { |
2206 | int ret, i, x; | 2123 | int ret, i, x; |
2207 | unsigned int hid0; | 2124 | unsigned int hid0; |
2208 | unsigned long p; | 2125 | unsigned long msr; |
2209 | struct adb_request sleep_req; | 2126 | struct adb_request sleep_req; |
2210 | void __iomem *mem_ctrl; | ||
2211 | unsigned int __iomem *mem_ctrl_sleep; | 2127 | unsigned int __iomem *mem_ctrl_sleep; |
2212 | 2128 | ||
2213 | /* first map in the memory controller registers */ | 2129 | if (pb3400_mem_ctrl == NULL) |
2214 | mem_ctrl = ioremap(PB3400_MEM_CTRL, 0x100); | ||
2215 | if (mem_ctrl == NULL) { | ||
2216 | printk("powerbook_sleep_3400: ioremap failed\n"); | ||
2217 | return -ENOMEM; | 2130 | return -ENOMEM; |
2218 | } | 2131 | mem_ctrl_sleep = pb3400_mem_ctrl + PB3400_MEM_CTRL_SLEEP; |
2219 | mem_ctrl_sleep = mem_ctrl + PB3400_MEM_CTRL_SLEEP; | ||
2220 | |||
2221 | /* Allocate room for PCI save */ | ||
2222 | pbook_alloc_pci_save(); | ||
2223 | 2132 | ||
2224 | ret = pmac_suspend_devices(); | 2133 | ret = pmac_suspend_devices(); |
2225 | if (ret) { | 2134 | if (ret) { |
2226 | pbook_free_pci_save(); | ||
2227 | printk(KERN_ERR "Sleep rejected by devices\n"); | 2135 | printk(KERN_ERR "Sleep rejected by devices\n"); |
2228 | return ret; | 2136 | return ret; |
2229 | } | 2137 | } |
2230 | 2138 | ||
2231 | /* Save the state of PCI config space for some slots */ | ||
2232 | pbook_pci_save(); | ||
2233 | |||
2234 | /* Set the memory controller to keep the memory refreshed | 2139 | /* Set the memory controller to keep the memory refreshed |
2235 | while we're asleep */ | 2140 | while we're asleep */ |
2236 | for (i = 0x403f; i >= 0x4000; --i) { | 2141 | for (i = 0x403f; i >= 0x4000; --i) { |
@@ -2244,36 +2149,31 @@ powerbook_sleep_3400(void) | |||
2244 | 2149 | ||
2245 | /* Ask the PMU to put us to sleep */ | 2150 | /* Ask the PMU to put us to sleep */ |
2246 | pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); | 2151 | pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); |
2247 | while (!sleep_req.complete) | 2152 | pmu_wait_complete(&sleep_req); |
2248 | mb(); | 2153 | pmu_unlock(); |
2249 | 2154 | ||
2250 | pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,1); | 2155 | pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 1); |
2251 | 2156 | ||
2252 | /* displacement-flush the L2 cache - necessary? */ | ||
2253 | for (p = KERNELBASE; p < KERNELBASE + 0x100000; p += 0x1000) | ||
2254 | i = *(volatile int *)p; | ||
2255 | asleep = 1; | 2157 | asleep = 1; |
2256 | 2158 | ||
2257 | /* Put the CPU into sleep mode */ | 2159 | /* Put the CPU into sleep mode */ |
2258 | hid0 = mfspr(SPRN_HID0); | 2160 | hid0 = mfspr(SPRN_HID0); |
2259 | hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP; | 2161 | hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP; |
2260 | mtspr(SPRN_HID0, hid0); | 2162 | mtspr(SPRN_HID0, hid0); |
2261 | mtmsr(mfmsr() | MSR_POW | MSR_EE); | 2163 | local_irq_enable(); |
2262 | udelay(10); | 2164 | msr = mfmsr() | MSR_POW; |
2165 | while (asleep) { | ||
2166 | mb(); | ||
2167 | mtmsr(msr); | ||
2168 | isync(); | ||
2169 | } | ||
2170 | local_irq_disable(); | ||
2263 | 2171 | ||
2264 | /* OK, we're awake again, start restoring things */ | 2172 | /* OK, we're awake again, start restoring things */ |
2265 | out_be32(mem_ctrl_sleep, 0x3f); | 2173 | out_be32(mem_ctrl_sleep, 0x3f); |
2266 | pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0); | 2174 | pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 0); |
2267 | pbook_pci_restore(); | ||
2268 | pmu_unlock(); | ||
2269 | |||
2270 | /* wait for the PMU interrupt sequence to complete */ | ||
2271 | while (asleep) | ||
2272 | mb(); | ||
2273 | 2175 | ||
2274 | pmac_wakeup_devices(); | 2176 | pmac_wakeup_devices(); |
2275 | pbook_free_pci_save(); | ||
2276 | iounmap(mem_ctrl); | ||
2277 | 2177 | ||
2278 | return 0; | 2178 | return 0; |
2279 | } | 2179 | } |