Commit 1fb25cb8 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Linus Torvalds

radeonfb: Fix resume from D3Cold on some platforms

For historical reason, this driver used its own saving/restoring
of the PCI config space, and used the state of it on resume as
an indication as to whether it needed to re-POST the chip or not.

This methods breaks with the later core changes since the core will
have restored things for us.

This patch fixes it by removing that custom code, using standard
core methods to save/restore state, and testing for the need to
re-POST by comparing the content of a few key PLL registers.
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent b746bb77
...@@ -2509,9 +2509,7 @@ static void radeon_reinitialize_QW(struct radeonfb_info *rinfo) ...@@ -2509,9 +2509,7 @@ static void radeon_reinitialize_QW(struct radeonfb_info *rinfo)
static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend) static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend)
{ {
u16 pwr_cmd;
u32 tmp; u32 tmp;
int i;
if (!rinfo->pm_reg) if (!rinfo->pm_reg)
return; return;
...@@ -2557,32 +2555,14 @@ static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend) ...@@ -2557,32 +2555,14 @@ static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend)
} }
} }
for (i = 0; i < 64; ++i)
pci_read_config_dword(rinfo->pdev, i * 4,
&rinfo->cfg_save[i]);
/* Switch PCI power management to D2. */ /* Switch PCI power management to D2. */
pci_disable_device(rinfo->pdev); pci_disable_device(rinfo->pdev);
for (;;) { pci_save_state(rinfo->pdev);
pci_read_config_word( pci_set_power_state(rinfo->pdev, PCI_D2);
rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL,
&pwr_cmd);
if (pwr_cmd & 2)
break;
pci_write_config_word(
rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL,
(pwr_cmd & ~PCI_PM_CTRL_STATE_MASK) | 2);
mdelay(500);
}
} else { } else {
printk(KERN_DEBUG "radeonfb (%s): switching to D0 state...\n", printk(KERN_DEBUG "radeonfb (%s): switching to D0 state...\n",
pci_name(rinfo->pdev)); pci_name(rinfo->pdev));
/* Switch back PCI powermanagment to D0 */
mdelay(200);
pci_write_config_word(rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL, 0);
mdelay(500);
if (rinfo->family <= CHIP_FAMILY_RV250) { if (rinfo->family <= CHIP_FAMILY_RV250) {
/* Reset the SDRAM controller */ /* Reset the SDRAM controller */
radeon_pm_full_reset_sdram(rinfo); radeon_pm_full_reset_sdram(rinfo);
...@@ -2598,37 +2578,10 @@ static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend) ...@@ -2598,37 +2578,10 @@ static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend)
} }
} }
static int radeon_restore_pci_cfg(struct radeonfb_info *rinfo)
{
int i;
static u32 radeon_cfg_after_resume[64];
for (i = 0; i < 64; ++i)
pci_read_config_dword(rinfo->pdev, i * 4,
&radeon_cfg_after_resume[i]);
if (radeon_cfg_after_resume[PCI_BASE_ADDRESS_0/4]
== rinfo->cfg_save[PCI_BASE_ADDRESS_0/4])
return 0; /* assume everything is ok */
for (i = PCI_BASE_ADDRESS_0/4; i < 64; ++i) {
if (radeon_cfg_after_resume[i] != rinfo->cfg_save[i])
pci_write_config_dword(rinfo->pdev, i * 4,
rinfo->cfg_save[i]);
}
pci_write_config_word(rinfo->pdev, PCI_CACHE_LINE_SIZE,
rinfo->cfg_save[PCI_CACHE_LINE_SIZE/4]);
pci_write_config_word(rinfo->pdev, PCI_COMMAND,
rinfo->cfg_save[PCI_COMMAND/4]);
return 1;
}
int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
{ {
struct fb_info *info = pci_get_drvdata(pdev); struct fb_info *info = pci_get_drvdata(pdev);
struct radeonfb_info *rinfo = info->par; struct radeonfb_info *rinfo = info->par;
int i;
if (mesg.event == pdev->dev.power.power_state.event) if (mesg.event == pdev->dev.power.power_state.event)
return 0; return 0;
...@@ -2674,6 +2627,11 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) ...@@ -2674,6 +2627,11 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
pmac_suspend_agp_for_card(pdev); pmac_suspend_agp_for_card(pdev);
#endif /* CONFIG_PPC_PMAC */ #endif /* CONFIG_PPC_PMAC */
/* It's unclear whether or when the generic code will do that, so let's
* do it ourselves. We save state before we do any power management
*/
pci_save_state(pdev);
/* If we support wakeup from poweroff, we save all regs we can including cfg /* If we support wakeup from poweroff, we save all regs we can including cfg
* space * space
*/ */
...@@ -2698,9 +2656,6 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) ...@@ -2698,9 +2656,6 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
mdelay(20); mdelay(20);
OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) & ~(LVDS_DIGON)); OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) & ~(LVDS_DIGON));
} }
// FIXME: Use PCI layer
for (i = 0; i < 64; ++i)
pci_read_config_dword(pdev, i * 4, &rinfo->cfg_save[i]);
pci_disable_device(pdev); pci_disable_device(pdev);
} }
/* If we support D2, we go to it (should be fixed later with a flag forcing /* If we support D2, we go to it (should be fixed later with a flag forcing
...@@ -2717,6 +2672,13 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) ...@@ -2717,6 +2672,13 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
return 0; return 0;
} }
static int radeon_check_power_loss(struct radeonfb_info *rinfo)
{
return rinfo->save_regs[4] != INPLL(CLK_PIN_CNTL) ||
rinfo->save_regs[2] != INPLL(MCLK_CNTL) ||
rinfo->save_regs[3] != INPLL(SCLK_CNTL);
}
int radeonfb_pci_resume(struct pci_dev *pdev) int radeonfb_pci_resume(struct pci_dev *pdev)
{ {
struct fb_info *info = pci_get_drvdata(pdev); struct fb_info *info = pci_get_drvdata(pdev);
...@@ -2735,20 +2697,13 @@ int radeonfb_pci_resume(struct pci_dev *pdev) ...@@ -2735,20 +2697,13 @@ int radeonfb_pci_resume(struct pci_dev *pdev)
printk(KERN_DEBUG "radeonfb (%s): resuming from state: %d...\n", printk(KERN_DEBUG "radeonfb (%s): resuming from state: %d...\n",
pci_name(pdev), pdev->dev.power.power_state.event); pci_name(pdev), pdev->dev.power.power_state.event);
/* PCI state will have been restored by the core, so
if (pci_enable_device(pdev)) { * we should be in D0 now with our config space fully
rc = -ENODEV; * restored
printk(KERN_ERR "radeonfb (%s): can't enable PCI device !\n", */
pci_name(pdev));
goto bail;
}
pci_set_master(pdev);
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
/* Wakeup chip. Check from config space if we were powered off /* Wakeup chip */
* (todo: additionally, check CLK_PIN_CNTL too) if ((rinfo->pm_mode & radeon_pm_off) && radeon_check_power_loss(rinfo)) {
*/
if ((rinfo->pm_mode & radeon_pm_off) && radeon_restore_pci_cfg(rinfo)) {
if (rinfo->reinit_func != NULL) if (rinfo->reinit_func != NULL)
rinfo->reinit_func(rinfo); rinfo->reinit_func(rinfo);
else { else {
......
...@@ -361,8 +361,6 @@ struct radeonfb_info { ...@@ -361,8 +361,6 @@ struct radeonfb_info {
#ifdef CONFIG_FB_RADEON_I2C #ifdef CONFIG_FB_RADEON_I2C
struct radeon_i2c_chan i2c[4]; struct radeon_i2c_chan i2c[4];
#endif #endif
u32 cfg_save[64];
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment