diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2005-05-01 11:58:42 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-05-01 11:58:42 -0400 |
commit | b20cc8aff258eea5a2339107605ebea949fa6ecf (patch) | |
tree | 0c860a2ca131233edeb1d4517e788a71990685df /arch | |
parent | 146a4b3bdfb5641bfbf975e29680b482b8b343ba (diff) |
[PATCH] ppc32: Fix a sleep issues on some laptops
Some earlier models of aluminium powerbooks and ibook G4s have a clock chip
that requires some tweaking before and after sleep. It seems that without
that magic incantation to disable and re-enable clock spreading, RAM isn't
properly refreshed during sleep. This fixes it.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/ppc/platforms/pmac_feature.c | 214 |
1 files changed, 114 insertions, 100 deletions
diff --git a/arch/ppc/platforms/pmac_feature.c b/arch/ppc/platforms/pmac_feature.c index 46cbf36722db..be41f6fa66a2 100644 --- a/arch/ppc/platforms/pmac_feature.c +++ b/arch/ppc/platforms/pmac_feature.c | |||
@@ -1590,6 +1590,112 @@ intrepid_shutdown(struct macio_chip* macio, int sleep_mode) | |||
1590 | mdelay(10); | 1590 | mdelay(10); |
1591 | } | 1591 | } |
1592 | 1592 | ||
1593 | |||
1594 | static void __pmac pmac_tweak_clock_spreading(struct macio_chip* macio, int enable) | ||
1595 | { | ||
1596 | /* Hack for doing clock spreading on some machines PowerBooks and | ||
1597 | * iBooks. This implements the "platform-do-clockspreading" OF | ||
1598 | * property as decoded manually on various models. For safety, we also | ||
1599 | * check the product ID in the device-tree in cases we'll whack the i2c | ||
1600 | * chip to make reasonably sure we won't set wrong values in there | ||
1601 | * | ||
1602 | * Of course, ultimately, we have to implement a real parser for | ||
1603 | * the platform-do-* stuff... | ||
1604 | */ | ||
1605 | |||
1606 | if (macio->type == macio_intrepid) { | ||
1607 | if (enable) | ||
1608 | UN_OUT(UNI_N_CLOCK_SPREADING, 2); | ||
1609 | else | ||
1610 | UN_OUT(UNI_N_CLOCK_SPREADING, 0); | ||
1611 | mdelay(40); | ||
1612 | } | ||
1613 | |||
1614 | while (machine_is_compatible("PowerBook5,2") || | ||
1615 | machine_is_compatible("PowerBook5,3") || | ||
1616 | machine_is_compatible("PowerBook6,2") || | ||
1617 | machine_is_compatible("PowerBook6,3")) { | ||
1618 | struct device_node *ui2c = of_find_node_by_type(NULL, "i2c"); | ||
1619 | struct device_node *dt = of_find_node_by_name(NULL, "device-tree"); | ||
1620 | u8 buffer[9]; | ||
1621 | u32 *productID; | ||
1622 | int i, rc, changed = 0; | ||
1623 | |||
1624 | if (dt == NULL) | ||
1625 | break; | ||
1626 | productID = (u32 *)get_property(dt, "pid#", NULL); | ||
1627 | if (productID == NULL) | ||
1628 | break; | ||
1629 | while(ui2c) { | ||
1630 | struct device_node *p = of_get_parent(ui2c); | ||
1631 | if (p && !strcmp(p->name, "uni-n")) | ||
1632 | break; | ||
1633 | ui2c = of_find_node_by_type(ui2c, "i2c"); | ||
1634 | } | ||
1635 | if (ui2c == NULL) | ||
1636 | break; | ||
1637 | DBG("Trying to bump clock speed for PID: %08x...\n", *productID); | ||
1638 | rc = pmac_low_i2c_open(ui2c, 1); | ||
1639 | if (rc != 0) | ||
1640 | break; | ||
1641 | pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined); | ||
1642 | rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9); | ||
1643 | DBG("read result: %d,", rc); | ||
1644 | if (rc != 0) { | ||
1645 | pmac_low_i2c_close(ui2c); | ||
1646 | break; | ||
1647 | } | ||
1648 | for (i=0; i<9; i++) | ||
1649 | DBG(" %02x", buffer[i]); | ||
1650 | DBG("\n"); | ||
1651 | |||
1652 | switch(*productID) { | ||
1653 | case 0x1182: /* AlBook 12" rev 2 */ | ||
1654 | case 0x1183: /* iBook G4 12" */ | ||
1655 | buffer[0] = (buffer[0] & 0x8f) | 0x70; | ||
1656 | buffer[2] = (buffer[2] & 0x7f) | 0x00; | ||
1657 | buffer[5] = (buffer[5] & 0x80) | 0x31; | ||
1658 | buffer[6] = (buffer[6] & 0x40) | 0xb0; | ||
1659 | buffer[7] = (buffer[7] & 0x00) | (enable ? 0xc0 : 0xba); | ||
1660 | buffer[8] = (buffer[8] & 0x00) | 0x30; | ||
1661 | changed = 1; | ||
1662 | break; | ||
1663 | case 0x3142: /* AlBook 15" (ATI M10) */ | ||
1664 | case 0x3143: /* AlBook 17" (ATI M10) */ | ||
1665 | buffer[0] = (buffer[0] & 0xaf) | 0x50; | ||
1666 | buffer[2] = (buffer[2] & 0x7f) | 0x00; | ||
1667 | buffer[5] = (buffer[5] & 0x80) | 0x31; | ||
1668 | buffer[6] = (buffer[6] & 0x40) | 0xb0; | ||
1669 | buffer[7] = (buffer[7] & 0x00) | (enable ? 0xd0 : 0xc0); | ||
1670 | buffer[8] = (buffer[8] & 0x00) | 0x30; | ||
1671 | changed = 1; | ||
1672 | break; | ||
1673 | default: | ||
1674 | DBG("i2c-hwclock: Machine model not handled\n"); | ||
1675 | break; | ||
1676 | } | ||
1677 | if (!changed) { | ||
1678 | pmac_low_i2c_close(ui2c); | ||
1679 | break; | ||
1680 | } | ||
1681 | pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_stdsub); | ||
1682 | rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_write, 0x80, buffer, 9); | ||
1683 | DBG("write result: %d,", rc); | ||
1684 | pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined); | ||
1685 | rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9); | ||
1686 | DBG("read result: %d,", rc); | ||
1687 | if (rc != 0) { | ||
1688 | pmac_low_i2c_close(ui2c); | ||
1689 | break; | ||
1690 | } | ||
1691 | for (i=0; i<9; i++) | ||
1692 | DBG(" %02x", buffer[i]); | ||
1693 | pmac_low_i2c_close(ui2c); | ||
1694 | break; | ||
1695 | } | ||
1696 | } | ||
1697 | |||
1698 | |||
1593 | static int __pmac | 1699 | static int __pmac |
1594 | core99_sleep(void) | 1700 | core99_sleep(void) |
1595 | { | 1701 | { |
@@ -1601,11 +1707,8 @@ core99_sleep(void) | |||
1601 | macio->type != macio_intrepid) | 1707 | macio->type != macio_intrepid) |
1602 | return -ENODEV; | 1708 | return -ENODEV; |
1603 | 1709 | ||
1604 | /* The device-tree contains that in the hwclock node */ | 1710 | /* Disable clock spreading */ |
1605 | if (macio->type == macio_intrepid) { | 1711 | pmac_tweak_clock_spreading(macio, 0); |
1606 | UN_OUT(UNI_N_CLOCK_SPREADING, 0); | ||
1607 | mdelay(40); | ||
1608 | } | ||
1609 | 1712 | ||
1610 | /* We power off the wireless slot in case it was not done | 1713 | /* We power off the wireless slot in case it was not done |
1611 | * by the driver. We don't power it on automatically however | 1714 | * by the driver. We don't power it on automatically however |
@@ -1749,11 +1852,8 @@ core99_wake_up(void) | |||
1749 | UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl); | 1852 | UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl); |
1750 | udelay(100); | 1853 | udelay(100); |
1751 | 1854 | ||
1752 | /* Restore clock spreading */ | 1855 | /* Enable clock spreading */ |
1753 | if (macio->type == macio_intrepid) { | 1856 | pmac_tweak_clock_spreading(macio, 1); |
1754 | UN_OUT(UNI_N_CLOCK_SPREADING, 2); | ||
1755 | mdelay(40); | ||
1756 | } | ||
1757 | 1857 | ||
1758 | return 0; | 1858 | return 0; |
1759 | } | 1859 | } |
@@ -2718,97 +2818,11 @@ set_initial_features(void) | |||
2718 | MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N); | 2818 | MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N); |
2719 | } | 2819 | } |
2720 | 2820 | ||
2721 | /* Hack for bumping clock speed on the new PowerBooks and the | 2821 | /* Some machine models need the clock chip to be properly setup for |
2722 | * iBook G4. This implements the "platform-do-clockspreading" OF | 2822 | * clock spreading now. This should be a platform function but we |
2723 | * property. For safety, we also check the product ID in the | 2823 | * don't do these at the moment |
2724 | * device-tree to make reasonably sure we won't set wrong values | ||
2725 | * in the clock chip. | ||
2726 | * | ||
2727 | * Of course, ultimately, we have to implement a real parser for | ||
2728 | * the platform-do-* stuff... | ||
2729 | */ | 2824 | */ |
2730 | while (machine_is_compatible("PowerBook5,2") || | 2825 | pmac_tweak_clock_spreading(&macio_chips[0], 1); |
2731 | machine_is_compatible("PowerBook5,3") || | ||
2732 | machine_is_compatible("PowerBook6,2") || | ||
2733 | machine_is_compatible("PowerBook6,3")) { | ||
2734 | struct device_node *ui2c = of_find_node_by_type(NULL, "i2c"); | ||
2735 | struct device_node *dt = of_find_node_by_name(NULL, "device-tree"); | ||
2736 | u8 buffer[9]; | ||
2737 | u32 *productID; | ||
2738 | int i, rc, changed = 0; | ||
2739 | |||
2740 | if (dt == NULL) | ||
2741 | break; | ||
2742 | productID = (u32 *)get_property(dt, "pid#", NULL); | ||
2743 | if (productID == NULL) | ||
2744 | break; | ||
2745 | while(ui2c) { | ||
2746 | struct device_node *p = of_get_parent(ui2c); | ||
2747 | if (p && !strcmp(p->name, "uni-n")) | ||
2748 | break; | ||
2749 | ui2c = of_find_node_by_type(ui2c, "i2c"); | ||
2750 | } | ||
2751 | if (ui2c == NULL) | ||
2752 | break; | ||
2753 | DBG("Trying to bump clock speed for PID: %08x...\n", *productID); | ||
2754 | rc = pmac_low_i2c_open(ui2c, 1); | ||
2755 | if (rc != 0) | ||
2756 | break; | ||
2757 | pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined); | ||
2758 | rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9); | ||
2759 | DBG("read result: %d,", rc); | ||
2760 | if (rc != 0) { | ||
2761 | pmac_low_i2c_close(ui2c); | ||
2762 | break; | ||
2763 | } | ||
2764 | for (i=0; i<9; i++) | ||
2765 | DBG(" %02x", buffer[i]); | ||
2766 | DBG("\n"); | ||
2767 | |||
2768 | switch(*productID) { | ||
2769 | case 0x1182: /* AlBook 12" rev 2 */ | ||
2770 | case 0x1183: /* iBook G4 12" */ | ||
2771 | buffer[0] = (buffer[0] & 0x8f) | 0x70; | ||
2772 | buffer[2] = (buffer[2] & 0x7f) | 0x00; | ||
2773 | buffer[5] = (buffer[5] & 0x80) | 0x31; | ||
2774 | buffer[6] = (buffer[6] & 0x40) | 0xb0; | ||
2775 | buffer[7] = (buffer[7] & 0x00) | 0xc0; | ||
2776 | buffer[8] = (buffer[8] & 0x00) | 0x30; | ||
2777 | changed = 1; | ||
2778 | break; | ||
2779 | case 0x3142: /* AlBook 15" (ATI M10) */ | ||
2780 | case 0x3143: /* AlBook 17" (ATI M10) */ | ||
2781 | buffer[0] = (buffer[0] & 0xaf) | 0x50; | ||
2782 | buffer[2] = (buffer[2] & 0x7f) | 0x00; | ||
2783 | buffer[5] = (buffer[5] & 0x80) | 0x31; | ||
2784 | buffer[6] = (buffer[6] & 0x40) | 0xb0; | ||
2785 | buffer[7] = (buffer[7] & 0x00) | 0xd0; | ||
2786 | buffer[8] = (buffer[8] & 0x00) | 0x30; | ||
2787 | changed = 1; | ||
2788 | break; | ||
2789 | default: | ||
2790 | DBG("i2c-hwclock: Machine model not handled\n"); | ||
2791 | break; | ||
2792 | } | ||
2793 | if (!changed) { | ||
2794 | pmac_low_i2c_close(ui2c); | ||
2795 | break; | ||
2796 | } | ||
2797 | pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_stdsub); | ||
2798 | rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_write, 0x80, buffer, 9); | ||
2799 | DBG("write result: %d,", rc); | ||
2800 | pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined); | ||
2801 | rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9); | ||
2802 | DBG("read result: %d,", rc); | ||
2803 | if (rc != 0) { | ||
2804 | pmac_low_i2c_close(ui2c); | ||
2805 | break; | ||
2806 | } | ||
2807 | for (i=0; i<9; i++) | ||
2808 | DBG(" %02x", buffer[i]); | ||
2809 | pmac_low_i2c_close(ui2c); | ||
2810 | break; | ||
2811 | } | ||
2812 | 2826 | ||
2813 | #endif /* CONFIG_POWER4 */ | 2827 | #endif /* CONFIG_POWER4 */ |
2814 | 2828 | ||