+static void sky2_power_state(struct sky2_hw *hw, pci_power_t state)
+{
+ u16 power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_CTRL);
+ int pex = pci_find_capability(hw->pdev, PCI_CAP_ID_EXP);
+ u32 reg;
+
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+
+ switch (state) {
+ case PCI_D0:
+ break;
+
+ case PCI_D1:
+ power_control |= 1;
+ break;
+
+ case PCI_D2:
+ power_control |= 2;
+ break;
+
+ case PCI_D3hot:
+ case PCI_D3cold:
+ power_control |= 3;
+ if (hw->flags & SKY2_HW_ADV_POWER_CTL) {
+ /* additional power saving measurements */
+ reg = sky2_pci_read32(hw, PCI_DEV_REG4);
+
+ /* set gating core clock for LTSSM in L1 state */
+ reg |= P_PEX_LTSSM_STAT(P_PEX_LTSSM_L1_STAT) |
+ /* auto clock gated scheme controlled by CLKREQ */
+ P_ASPM_A1_MODE_SELECT |
+ /* enable Gate Root Core Clock */
+ P_CLK_GATE_ROOT_COR_ENA;
+
+ if (pex && (hw->flags & SKY2_HW_CLK_POWER)) {
+ /* enable Clock Power Management (CLKREQ) */
+ u16 ctrl = sky2_pci_read16(hw, pex + PCI_EXP_DEVCTL);
+
+ ctrl |= PCI_EXP_DEVCTL_AUX_PME;
+ sky2_pci_write16(hw, pex + PCI_EXP_DEVCTL, ctrl);
+ } else
+ /* force CLKREQ Enable in Our4 (A1b only) */
+ reg |= P_ASPM_FORCE_CLKREQ_ENA;
+
+ /* set Mask Register for Release/Gate Clock */
+ sky2_pci_write32(hw, PCI_DEV_REG5,
+ P_REL_PCIE_EXIT_L1_ST | P_GAT_PCIE_ENTER_L1_ST |
+ P_REL_PCIE_RX_EX_IDLE | P_GAT_PCIE_RX_EL_IDLE |
+ P_REL_GPHY_LINK_UP | P_GAT_GPHY_LINK_DOWN);
+ } else
+ sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_CLK_HALT);
+
+ /* put CPU into reset state */
+ sky2_write8(hw, B28_Y2_ASF_STAT_CMD, HCU_CCSR_ASF_RESET);
+ if (hw->chip_id == CHIP_ID_YUKON_SUPR && hw->chip_rev == CHIP_REV_YU_SU_A0)
+ /* put CPU into halt state */
+ sky2_write8(hw, B28_Y2_ASF_STAT_CMD, HCU_CCSR_ASF_HALTED);
+
+ if (pex && !(hw->flags & SKY2_HW_RAM_BUFFER)) {
+ reg = sky2_pci_read32(hw, PCI_DEV_REG1);
+ /* force to PCIe L1 */
+ reg |= PCI_FORCE_PEX_L1;
+ sky2_pci_write32(hw, PCI_DEV_REG1, reg);
+ }
+ break;
+
+ default:
+ dev_warn(&hw->pdev->dev, PFX "Invalid power state (%d) ",
+ state);
+ return;
+ }
+
+ power_control |= PCI_PM_CTRL_PME_ENABLE;
+ /* Finally, set the new power state. */
+ sky2_pci_write32(hw, hw->pm_cap + PCI_PM_CTRL, power_control);
+
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+ sky2_pci_read32(hw, B0_CTST);
+}
+