18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: MIT 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright © 2020 Intel Corporation 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/kernel.h> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <drm/drm_print.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "i915_drv.h" 118c2ecf20Sopenharmony_ci#include "i915_reg.h" 128c2ecf20Sopenharmony_ci#include "i915_trace.h" 138c2ecf20Sopenharmony_ci#include "i915_utils.h" 148c2ecf20Sopenharmony_ci#include "intel_pm.h" 158c2ecf20Sopenharmony_ci#include "vlv_suspend.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistruct vlv_s0ix_state { 188c2ecf20Sopenharmony_ci /* GAM */ 198c2ecf20Sopenharmony_ci u32 wr_watermark; 208c2ecf20Sopenharmony_ci u32 gfx_prio_ctrl; 218c2ecf20Sopenharmony_ci u32 arb_mode; 228c2ecf20Sopenharmony_ci u32 gfx_pend_tlb0; 238c2ecf20Sopenharmony_ci u32 gfx_pend_tlb1; 248c2ecf20Sopenharmony_ci u32 lra_limits[GEN7_LRA_LIMITS_REG_NUM]; 258c2ecf20Sopenharmony_ci u32 media_max_req_count; 268c2ecf20Sopenharmony_ci u32 gfx_max_req_count; 278c2ecf20Sopenharmony_ci u32 render_hwsp; 288c2ecf20Sopenharmony_ci u32 ecochk; 298c2ecf20Sopenharmony_ci u32 bsd_hwsp; 308c2ecf20Sopenharmony_ci u32 blt_hwsp; 318c2ecf20Sopenharmony_ci u32 tlb_rd_addr; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci /* MBC */ 348c2ecf20Sopenharmony_ci u32 g3dctl; 358c2ecf20Sopenharmony_ci u32 gsckgctl; 368c2ecf20Sopenharmony_ci u32 mbctl; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci /* GCP */ 398c2ecf20Sopenharmony_ci u32 ucgctl1; 408c2ecf20Sopenharmony_ci u32 ucgctl3; 418c2ecf20Sopenharmony_ci u32 rcgctl1; 428c2ecf20Sopenharmony_ci u32 rcgctl2; 438c2ecf20Sopenharmony_ci u32 rstctl; 448c2ecf20Sopenharmony_ci u32 misccpctl; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci /* GPM */ 478c2ecf20Sopenharmony_ci u32 gfxpause; 488c2ecf20Sopenharmony_ci u32 rpdeuhwtc; 498c2ecf20Sopenharmony_ci u32 rpdeuc; 508c2ecf20Sopenharmony_ci u32 ecobus; 518c2ecf20Sopenharmony_ci u32 pwrdwnupctl; 528c2ecf20Sopenharmony_ci u32 rp_down_timeout; 538c2ecf20Sopenharmony_ci u32 rp_deucsw; 548c2ecf20Sopenharmony_ci u32 rcubmabdtmr; 558c2ecf20Sopenharmony_ci u32 rcedata; 568c2ecf20Sopenharmony_ci u32 spare2gh; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci /* Display 1 CZ domain */ 598c2ecf20Sopenharmony_ci u32 gt_imr; 608c2ecf20Sopenharmony_ci u32 gt_ier; 618c2ecf20Sopenharmony_ci u32 pm_imr; 628c2ecf20Sopenharmony_ci u32 pm_ier; 638c2ecf20Sopenharmony_ci u32 gt_scratch[GEN7_GT_SCRATCH_REG_NUM]; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* GT SA CZ domain */ 668c2ecf20Sopenharmony_ci u32 tilectl; 678c2ecf20Sopenharmony_ci u32 gt_fifoctl; 688c2ecf20Sopenharmony_ci u32 gtlc_wake_ctrl; 698c2ecf20Sopenharmony_ci u32 gtlc_survive; 708c2ecf20Sopenharmony_ci u32 pmwgicz; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci /* Display 2 CZ domain */ 738c2ecf20Sopenharmony_ci u32 gu_ctl0; 748c2ecf20Sopenharmony_ci u32 gu_ctl1; 758c2ecf20Sopenharmony_ci u32 pcbr; 768c2ecf20Sopenharmony_ci u32 clock_gate_dis2; 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/* 808c2ecf20Sopenharmony_ci * Save all Gunit registers that may be lost after a D3 and a subsequent 818c2ecf20Sopenharmony_ci * S0i[R123] transition. The list of registers needing a save/restore is 828c2ecf20Sopenharmony_ci * defined in the VLV2_S0IXRegs document. This documents marks all Gunit 838c2ecf20Sopenharmony_ci * registers in the following way: 848c2ecf20Sopenharmony_ci * - Driver: saved/restored by the driver 858c2ecf20Sopenharmony_ci * - Punit : saved/restored by the Punit firmware 868c2ecf20Sopenharmony_ci * - No, w/o marking: no need to save/restore, since the register is R/O or 878c2ecf20Sopenharmony_ci * used internally by the HW in a way that doesn't depend 888c2ecf20Sopenharmony_ci * keeping the content across a suspend/resume. 898c2ecf20Sopenharmony_ci * - Debug : used for debugging 908c2ecf20Sopenharmony_ci * 918c2ecf20Sopenharmony_ci * We save/restore all registers marked with 'Driver', with the following 928c2ecf20Sopenharmony_ci * exceptions: 938c2ecf20Sopenharmony_ci * - Registers out of use, including also registers marked with 'Debug'. 948c2ecf20Sopenharmony_ci * These have no effect on the driver's operation, so we don't save/restore 958c2ecf20Sopenharmony_ci * them to reduce the overhead. 968c2ecf20Sopenharmony_ci * - Registers that are fully setup by an initialization function called from 978c2ecf20Sopenharmony_ci * the resume path. For example many clock gating and RPS/RC6 registers. 988c2ecf20Sopenharmony_ci * - Registers that provide the right functionality with their reset defaults. 998c2ecf20Sopenharmony_ci * 1008c2ecf20Sopenharmony_ci * TODO: Except for registers that based on the above 3 criteria can be safely 1018c2ecf20Sopenharmony_ci * ignored, we save/restore all others, practically treating the HW context as 1028c2ecf20Sopenharmony_ci * a black-box for the driver. Further investigation is needed to reduce the 1038c2ecf20Sopenharmony_ci * saved/restored registers even further, by following the same 3 criteria. 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_cistatic void vlv_save_gunit_s0ix_state(struct drm_i915_private *i915) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct vlv_s0ix_state *s = i915->vlv_s0ix_state; 1088c2ecf20Sopenharmony_ci struct intel_uncore *uncore = &i915->uncore; 1098c2ecf20Sopenharmony_ci int i; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (!s) 1128c2ecf20Sopenharmony_ci return; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* GAM 0x4000-0x4770 */ 1158c2ecf20Sopenharmony_ci s->wr_watermark = intel_uncore_read(uncore, GEN7_WR_WATERMARK); 1168c2ecf20Sopenharmony_ci s->gfx_prio_ctrl = intel_uncore_read(uncore, GEN7_GFX_PRIO_CTRL); 1178c2ecf20Sopenharmony_ci s->arb_mode = intel_uncore_read(uncore, ARB_MODE); 1188c2ecf20Sopenharmony_ci s->gfx_pend_tlb0 = intel_uncore_read(uncore, GEN7_GFX_PEND_TLB0); 1198c2ecf20Sopenharmony_ci s->gfx_pend_tlb1 = intel_uncore_read(uncore, GEN7_GFX_PEND_TLB1); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(s->lra_limits); i++) 1228c2ecf20Sopenharmony_ci s->lra_limits[i] = intel_uncore_read(uncore, GEN7_LRA_LIMITS(i)); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci s->media_max_req_count = intel_uncore_read(uncore, GEN7_MEDIA_MAX_REQ_COUNT); 1258c2ecf20Sopenharmony_ci s->gfx_max_req_count = intel_uncore_read(uncore, GEN7_GFX_MAX_REQ_COUNT); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci s->render_hwsp = intel_uncore_read(uncore, RENDER_HWS_PGA_GEN7); 1288c2ecf20Sopenharmony_ci s->ecochk = intel_uncore_read(uncore, GAM_ECOCHK); 1298c2ecf20Sopenharmony_ci s->bsd_hwsp = intel_uncore_read(uncore, BSD_HWS_PGA_GEN7); 1308c2ecf20Sopenharmony_ci s->blt_hwsp = intel_uncore_read(uncore, BLT_HWS_PGA_GEN7); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci s->tlb_rd_addr = intel_uncore_read(uncore, GEN7_TLB_RD_ADDR); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* MBC 0x9024-0x91D0, 0x8500 */ 1358c2ecf20Sopenharmony_ci s->g3dctl = intel_uncore_read(uncore, VLV_G3DCTL); 1368c2ecf20Sopenharmony_ci s->gsckgctl = intel_uncore_read(uncore, VLV_GSCKGCTL); 1378c2ecf20Sopenharmony_ci s->mbctl = intel_uncore_read(uncore, GEN6_MBCTL); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* GCP 0x9400-0x9424, 0x8100-0x810C */ 1408c2ecf20Sopenharmony_ci s->ucgctl1 = intel_uncore_read(uncore, GEN6_UCGCTL1); 1418c2ecf20Sopenharmony_ci s->ucgctl3 = intel_uncore_read(uncore, GEN6_UCGCTL3); 1428c2ecf20Sopenharmony_ci s->rcgctl1 = intel_uncore_read(uncore, GEN6_RCGCTL1); 1438c2ecf20Sopenharmony_ci s->rcgctl2 = intel_uncore_read(uncore, GEN6_RCGCTL2); 1448c2ecf20Sopenharmony_ci s->rstctl = intel_uncore_read(uncore, GEN6_RSTCTL); 1458c2ecf20Sopenharmony_ci s->misccpctl = intel_uncore_read(uncore, GEN7_MISCCPCTL); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* GPM 0xA000-0xAA84, 0x8000-0x80FC */ 1488c2ecf20Sopenharmony_ci s->gfxpause = intel_uncore_read(uncore, GEN6_GFXPAUSE); 1498c2ecf20Sopenharmony_ci s->rpdeuhwtc = intel_uncore_read(uncore, GEN6_RPDEUHWTC); 1508c2ecf20Sopenharmony_ci s->rpdeuc = intel_uncore_read(uncore, GEN6_RPDEUC); 1518c2ecf20Sopenharmony_ci s->ecobus = intel_uncore_read(uncore, ECOBUS); 1528c2ecf20Sopenharmony_ci s->pwrdwnupctl = intel_uncore_read(uncore, VLV_PWRDWNUPCTL); 1538c2ecf20Sopenharmony_ci s->rp_down_timeout = intel_uncore_read(uncore, GEN6_RP_DOWN_TIMEOUT); 1548c2ecf20Sopenharmony_ci s->rp_deucsw = intel_uncore_read(uncore, GEN6_RPDEUCSW); 1558c2ecf20Sopenharmony_ci s->rcubmabdtmr = intel_uncore_read(uncore, GEN6_RCUBMABDTMR); 1568c2ecf20Sopenharmony_ci s->rcedata = intel_uncore_read(uncore, VLV_RCEDATA); 1578c2ecf20Sopenharmony_ci s->spare2gh = intel_uncore_read(uncore, VLV_SPAREG2H); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* Display CZ domain, 0x4400C-0x4402C, 0x4F000-0x4F11F */ 1608c2ecf20Sopenharmony_ci s->gt_imr = intel_uncore_read(uncore, GTIMR); 1618c2ecf20Sopenharmony_ci s->gt_ier = intel_uncore_read(uncore, GTIER); 1628c2ecf20Sopenharmony_ci s->pm_imr = intel_uncore_read(uncore, GEN6_PMIMR); 1638c2ecf20Sopenharmony_ci s->pm_ier = intel_uncore_read(uncore, GEN6_PMIER); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(s->gt_scratch); i++) 1668c2ecf20Sopenharmony_ci s->gt_scratch[i] = intel_uncore_read(uncore, GEN7_GT_SCRATCH(i)); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* GT SA CZ domain, 0x100000-0x138124 */ 1698c2ecf20Sopenharmony_ci s->tilectl = intel_uncore_read(uncore, TILECTL); 1708c2ecf20Sopenharmony_ci s->gt_fifoctl = intel_uncore_read(uncore, GTFIFOCTL); 1718c2ecf20Sopenharmony_ci s->gtlc_wake_ctrl = intel_uncore_read(uncore, VLV_GTLC_WAKE_CTRL); 1728c2ecf20Sopenharmony_ci s->gtlc_survive = intel_uncore_read(uncore, VLV_GTLC_SURVIVABILITY_REG); 1738c2ecf20Sopenharmony_ci s->pmwgicz = intel_uncore_read(uncore, VLV_PMWGICZ); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* Gunit-Display CZ domain, 0x182028-0x1821CF */ 1768c2ecf20Sopenharmony_ci s->gu_ctl0 = intel_uncore_read(uncore, VLV_GU_CTL0); 1778c2ecf20Sopenharmony_ci s->gu_ctl1 = intel_uncore_read(uncore, VLV_GU_CTL1); 1788c2ecf20Sopenharmony_ci s->pcbr = intel_uncore_read(uncore, VLV_PCBR); 1798c2ecf20Sopenharmony_ci s->clock_gate_dis2 = intel_uncore_read(uncore, VLV_GUNIT_CLOCK_GATE2); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci /* 1828c2ecf20Sopenharmony_ci * Not saving any of: 1838c2ecf20Sopenharmony_ci * DFT, 0x9800-0x9EC0 1848c2ecf20Sopenharmony_ci * SARB, 0xB000-0xB1FC 1858c2ecf20Sopenharmony_ci * GAC, 0x5208-0x524C, 0x14000-0x14C000 1868c2ecf20Sopenharmony_ci * PCI CFG 1878c2ecf20Sopenharmony_ci */ 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic void vlv_restore_gunit_s0ix_state(struct drm_i915_private *i915) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci struct vlv_s0ix_state *s = i915->vlv_s0ix_state; 1938c2ecf20Sopenharmony_ci struct intel_uncore *uncore = &i915->uncore; 1948c2ecf20Sopenharmony_ci u32 val; 1958c2ecf20Sopenharmony_ci int i; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (!s) 1988c2ecf20Sopenharmony_ci return; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci /* GAM 0x4000-0x4770 */ 2018c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GEN7_WR_WATERMARK, s->wr_watermark); 2028c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GEN7_GFX_PRIO_CTRL, s->gfx_prio_ctrl); 2038c2ecf20Sopenharmony_ci intel_uncore_write(uncore, ARB_MODE, s->arb_mode | (0xffff << 16)); 2048c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GEN7_GFX_PEND_TLB0, s->gfx_pend_tlb0); 2058c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GEN7_GFX_PEND_TLB1, s->gfx_pend_tlb1); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(s->lra_limits); i++) 2088c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GEN7_LRA_LIMITS(i), s->lra_limits[i]); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GEN7_MEDIA_MAX_REQ_COUNT, s->media_max_req_count); 2118c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GEN7_GFX_MAX_REQ_COUNT, s->gfx_max_req_count); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci intel_uncore_write(uncore, RENDER_HWS_PGA_GEN7, s->render_hwsp); 2148c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GAM_ECOCHK, s->ecochk); 2158c2ecf20Sopenharmony_ci intel_uncore_write(uncore, BSD_HWS_PGA_GEN7, s->bsd_hwsp); 2168c2ecf20Sopenharmony_ci intel_uncore_write(uncore, BLT_HWS_PGA_GEN7, s->blt_hwsp); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GEN7_TLB_RD_ADDR, s->tlb_rd_addr); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* MBC 0x9024-0x91D0, 0x8500 */ 2218c2ecf20Sopenharmony_ci intel_uncore_write(uncore, VLV_G3DCTL, s->g3dctl); 2228c2ecf20Sopenharmony_ci intel_uncore_write(uncore, VLV_GSCKGCTL, s->gsckgctl); 2238c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GEN6_MBCTL, s->mbctl); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* GCP 0x9400-0x9424, 0x8100-0x810C */ 2268c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GEN6_UCGCTL1, s->ucgctl1); 2278c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GEN6_UCGCTL3, s->ucgctl3); 2288c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GEN6_RCGCTL1, s->rcgctl1); 2298c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GEN6_RCGCTL2, s->rcgctl2); 2308c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GEN6_RSTCTL, s->rstctl); 2318c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GEN7_MISCCPCTL, s->misccpctl); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci /* GPM 0xA000-0xAA84, 0x8000-0x80FC */ 2348c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GEN6_GFXPAUSE, s->gfxpause); 2358c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GEN6_RPDEUHWTC, s->rpdeuhwtc); 2368c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GEN6_RPDEUC, s->rpdeuc); 2378c2ecf20Sopenharmony_ci intel_uncore_write(uncore, ECOBUS, s->ecobus); 2388c2ecf20Sopenharmony_ci intel_uncore_write(uncore, VLV_PWRDWNUPCTL, s->pwrdwnupctl); 2398c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GEN6_RP_DOWN_TIMEOUT, s->rp_down_timeout); 2408c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GEN6_RPDEUCSW, s->rp_deucsw); 2418c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GEN6_RCUBMABDTMR, s->rcubmabdtmr); 2428c2ecf20Sopenharmony_ci intel_uncore_write(uncore, VLV_RCEDATA, s->rcedata); 2438c2ecf20Sopenharmony_ci intel_uncore_write(uncore, VLV_SPAREG2H, s->spare2gh); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* Display CZ domain, 0x4400C-0x4402C, 0x4F000-0x4F11F */ 2468c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GTIMR, s->gt_imr); 2478c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GTIER, s->gt_ier); 2488c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GEN6_PMIMR, s->pm_imr); 2498c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GEN6_PMIER, s->pm_ier); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(s->gt_scratch); i++) 2528c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GEN7_GT_SCRATCH(i), s->gt_scratch[i]); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci /* GT SA CZ domain, 0x100000-0x138124 */ 2558c2ecf20Sopenharmony_ci intel_uncore_write(uncore, TILECTL, s->tilectl); 2568c2ecf20Sopenharmony_ci intel_uncore_write(uncore, GTFIFOCTL, s->gt_fifoctl); 2578c2ecf20Sopenharmony_ci /* 2588c2ecf20Sopenharmony_ci * Preserve the GT allow wake and GFX force clock bit, they are not 2598c2ecf20Sopenharmony_ci * be restored, as they are used to control the s0ix suspend/resume 2608c2ecf20Sopenharmony_ci * sequence by the caller. 2618c2ecf20Sopenharmony_ci */ 2628c2ecf20Sopenharmony_ci val = intel_uncore_read(uncore, VLV_GTLC_WAKE_CTRL); 2638c2ecf20Sopenharmony_ci val &= VLV_GTLC_ALLOWWAKEREQ; 2648c2ecf20Sopenharmony_ci val |= s->gtlc_wake_ctrl & ~VLV_GTLC_ALLOWWAKEREQ; 2658c2ecf20Sopenharmony_ci intel_uncore_write(uncore, VLV_GTLC_WAKE_CTRL, val); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci val = intel_uncore_read(uncore, VLV_GTLC_SURVIVABILITY_REG); 2688c2ecf20Sopenharmony_ci val &= VLV_GFX_CLK_FORCE_ON_BIT; 2698c2ecf20Sopenharmony_ci val |= s->gtlc_survive & ~VLV_GFX_CLK_FORCE_ON_BIT; 2708c2ecf20Sopenharmony_ci intel_uncore_write(uncore, VLV_GTLC_SURVIVABILITY_REG, val); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci intel_uncore_write(uncore, VLV_PMWGICZ, s->pmwgicz); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* Gunit-Display CZ domain, 0x182028-0x1821CF */ 2758c2ecf20Sopenharmony_ci intel_uncore_write(uncore, VLV_GU_CTL0, s->gu_ctl0); 2768c2ecf20Sopenharmony_ci intel_uncore_write(uncore, VLV_GU_CTL1, s->gu_ctl1); 2778c2ecf20Sopenharmony_ci intel_uncore_write(uncore, VLV_PCBR, s->pcbr); 2788c2ecf20Sopenharmony_ci intel_uncore_write(uncore, VLV_GUNIT_CLOCK_GATE2, s->clock_gate_dis2); 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic int vlv_wait_for_pw_status(struct drm_i915_private *i915, 2828c2ecf20Sopenharmony_ci u32 mask, u32 val) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci i915_reg_t reg = VLV_GTLC_PW_STATUS; 2858c2ecf20Sopenharmony_ci u32 reg_value; 2868c2ecf20Sopenharmony_ci int ret; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* The HW does not like us polling for PW_STATUS frequently, so 2898c2ecf20Sopenharmony_ci * use the sleeping loop rather than risk the busy spin within 2908c2ecf20Sopenharmony_ci * intel_wait_for_register(). 2918c2ecf20Sopenharmony_ci * 2928c2ecf20Sopenharmony_ci * Transitioning between RC6 states should be at most 2ms (see 2938c2ecf20Sopenharmony_ci * valleyview_enable_rps) so use a 3ms timeout. 2948c2ecf20Sopenharmony_ci */ 2958c2ecf20Sopenharmony_ci ret = wait_for(((reg_value = 2968c2ecf20Sopenharmony_ci intel_uncore_read_notrace(&i915->uncore, reg)) & mask) 2978c2ecf20Sopenharmony_ci == val, 3); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* just trace the final value */ 3008c2ecf20Sopenharmony_ci trace_i915_reg_rw(false, reg, reg_value, sizeof(reg_value), true); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return ret; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic int vlv_force_gfx_clock(struct drm_i915_private *i915, bool force_on) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci struct intel_uncore *uncore = &i915->uncore; 3088c2ecf20Sopenharmony_ci u32 val; 3098c2ecf20Sopenharmony_ci int err; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci val = intel_uncore_read(uncore, VLV_GTLC_SURVIVABILITY_REG); 3128c2ecf20Sopenharmony_ci val &= ~VLV_GFX_CLK_FORCE_ON_BIT; 3138c2ecf20Sopenharmony_ci if (force_on) 3148c2ecf20Sopenharmony_ci val |= VLV_GFX_CLK_FORCE_ON_BIT; 3158c2ecf20Sopenharmony_ci intel_uncore_write(uncore, VLV_GTLC_SURVIVABILITY_REG, val); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (!force_on) 3188c2ecf20Sopenharmony_ci return 0; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci err = intel_wait_for_register(uncore, 3218c2ecf20Sopenharmony_ci VLV_GTLC_SURVIVABILITY_REG, 3228c2ecf20Sopenharmony_ci VLV_GFX_CLK_STATUS_BIT, 3238c2ecf20Sopenharmony_ci VLV_GFX_CLK_STATUS_BIT, 3248c2ecf20Sopenharmony_ci 20); 3258c2ecf20Sopenharmony_ci if (err) 3268c2ecf20Sopenharmony_ci drm_err(&i915->drm, 3278c2ecf20Sopenharmony_ci "timeout waiting for GFX clock force-on (%08x)\n", 3288c2ecf20Sopenharmony_ci intel_uncore_read(uncore, VLV_GTLC_SURVIVABILITY_REG)); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci return err; 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic int vlv_allow_gt_wake(struct drm_i915_private *i915, bool allow) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci struct intel_uncore *uncore = &i915->uncore; 3368c2ecf20Sopenharmony_ci u32 mask; 3378c2ecf20Sopenharmony_ci u32 val; 3388c2ecf20Sopenharmony_ci int err; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci val = intel_uncore_read(uncore, VLV_GTLC_WAKE_CTRL); 3418c2ecf20Sopenharmony_ci val &= ~VLV_GTLC_ALLOWWAKEREQ; 3428c2ecf20Sopenharmony_ci if (allow) 3438c2ecf20Sopenharmony_ci val |= VLV_GTLC_ALLOWWAKEREQ; 3448c2ecf20Sopenharmony_ci intel_uncore_write(uncore, VLV_GTLC_WAKE_CTRL, val); 3458c2ecf20Sopenharmony_ci intel_uncore_posting_read(uncore, VLV_GTLC_WAKE_CTRL); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci mask = VLV_GTLC_ALLOWWAKEACK; 3488c2ecf20Sopenharmony_ci val = allow ? mask : 0; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci err = vlv_wait_for_pw_status(i915, mask, val); 3518c2ecf20Sopenharmony_ci if (err) 3528c2ecf20Sopenharmony_ci drm_err(&i915->drm, "timeout disabling GT waking\n"); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci return err; 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic void vlv_wait_for_gt_wells(struct drm_i915_private *dev_priv, 3588c2ecf20Sopenharmony_ci bool wait_for_on) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci u32 mask; 3618c2ecf20Sopenharmony_ci u32 val; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci mask = VLV_GTLC_PW_MEDIA_STATUS_MASK | VLV_GTLC_PW_RENDER_STATUS_MASK; 3648c2ecf20Sopenharmony_ci val = wait_for_on ? mask : 0; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* 3678c2ecf20Sopenharmony_ci * RC6 transitioning can be delayed up to 2 msec (see 3688c2ecf20Sopenharmony_ci * valleyview_enable_rps), use 3 msec for safety. 3698c2ecf20Sopenharmony_ci * 3708c2ecf20Sopenharmony_ci * This can fail to turn off the rc6 if the GPU is stuck after a failed 3718c2ecf20Sopenharmony_ci * reset and we are trying to force the machine to sleep. 3728c2ecf20Sopenharmony_ci */ 3738c2ecf20Sopenharmony_ci if (vlv_wait_for_pw_status(dev_priv, mask, val)) 3748c2ecf20Sopenharmony_ci drm_dbg(&dev_priv->drm, 3758c2ecf20Sopenharmony_ci "timeout waiting for GT wells to go %s\n", 3768c2ecf20Sopenharmony_ci onoff(wait_for_on)); 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic void vlv_check_no_gt_access(struct drm_i915_private *i915) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci struct intel_uncore *uncore = &i915->uncore; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci if (!(intel_uncore_read(uncore, VLV_GTLC_PW_STATUS) & VLV_GTLC_ALLOWWAKEERR)) 3848c2ecf20Sopenharmony_ci return; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci drm_dbg(&i915->drm, "GT register access while GT waking disabled\n"); 3878c2ecf20Sopenharmony_ci intel_uncore_write(uncore, VLV_GTLC_PW_STATUS, VLV_GTLC_ALLOWWAKEERR); 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ciint vlv_suspend_complete(struct drm_i915_private *dev_priv) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci u32 mask; 3938c2ecf20Sopenharmony_ci int err; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv)) 3968c2ecf20Sopenharmony_ci return 0; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci /* 3998c2ecf20Sopenharmony_ci * Bspec defines the following GT well on flags as debug only, so 4008c2ecf20Sopenharmony_ci * don't treat them as hard failures. 4018c2ecf20Sopenharmony_ci */ 4028c2ecf20Sopenharmony_ci vlv_wait_for_gt_wells(dev_priv, false); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci mask = VLV_GTLC_RENDER_CTX_EXISTS | VLV_GTLC_MEDIA_CTX_EXISTS; 4058c2ecf20Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, 4068c2ecf20Sopenharmony_ci (intel_uncore_read(&dev_priv->uncore, VLV_GTLC_WAKE_CTRL) & mask) != mask); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci vlv_check_no_gt_access(dev_priv); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci err = vlv_force_gfx_clock(dev_priv, true); 4118c2ecf20Sopenharmony_ci if (err) 4128c2ecf20Sopenharmony_ci goto err1; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci err = vlv_allow_gt_wake(dev_priv, false); 4158c2ecf20Sopenharmony_ci if (err) 4168c2ecf20Sopenharmony_ci goto err2; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci vlv_save_gunit_s0ix_state(dev_priv); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci err = vlv_force_gfx_clock(dev_priv, false); 4218c2ecf20Sopenharmony_ci if (err) 4228c2ecf20Sopenharmony_ci goto err2; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci return 0; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cierr2: 4278c2ecf20Sopenharmony_ci /* For safety always re-enable waking and disable gfx clock forcing */ 4288c2ecf20Sopenharmony_ci vlv_allow_gt_wake(dev_priv, true); 4298c2ecf20Sopenharmony_cierr1: 4308c2ecf20Sopenharmony_ci vlv_force_gfx_clock(dev_priv, false); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci return err; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ciint vlv_resume_prepare(struct drm_i915_private *dev_priv, bool rpm_resume) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci int err; 4388c2ecf20Sopenharmony_ci int ret; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv)) 4418c2ecf20Sopenharmony_ci return 0; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci /* 4448c2ecf20Sopenharmony_ci * If any of the steps fail just try to continue, that's the best we 4458c2ecf20Sopenharmony_ci * can do at this point. Return the first error code (which will also 4468c2ecf20Sopenharmony_ci * leave RPM permanently disabled). 4478c2ecf20Sopenharmony_ci */ 4488c2ecf20Sopenharmony_ci ret = vlv_force_gfx_clock(dev_priv, true); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci vlv_restore_gunit_s0ix_state(dev_priv); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci err = vlv_allow_gt_wake(dev_priv, true); 4538c2ecf20Sopenharmony_ci if (!ret) 4548c2ecf20Sopenharmony_ci ret = err; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci err = vlv_force_gfx_clock(dev_priv, false); 4578c2ecf20Sopenharmony_ci if (!ret) 4588c2ecf20Sopenharmony_ci ret = err; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci vlv_check_no_gt_access(dev_priv); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci if (rpm_resume) 4638c2ecf20Sopenharmony_ci intel_init_clock_gating(dev_priv); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci return ret; 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ciint vlv_suspend_init(struct drm_i915_private *i915) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci if (!IS_VALLEYVIEW(i915)) 4718c2ecf20Sopenharmony_ci return 0; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci /* we write all the values in the struct, so no need to zero it out */ 4748c2ecf20Sopenharmony_ci i915->vlv_s0ix_state = kmalloc(sizeof(*i915->vlv_s0ix_state), 4758c2ecf20Sopenharmony_ci GFP_KERNEL); 4768c2ecf20Sopenharmony_ci if (!i915->vlv_s0ix_state) 4778c2ecf20Sopenharmony_ci return -ENOMEM; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci return 0; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_civoid vlv_suspend_cleanup(struct drm_i915_private *i915) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci if (!i915->vlv_s0ix_state) 4858c2ecf20Sopenharmony_ci return; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci kfree(i915->vlv_s0ix_state); 4888c2ecf20Sopenharmony_ci i915->vlv_s0ix_state = NULL; 4898c2ecf20Sopenharmony_ci} 490