hc
2024-03-25 edb30157bad0c0001c32b854271ace01d3b9a16a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/** @file
File to contain all the hardware specific stuff for the Smm Sx dispatch protocol.
 
Copyright (c) 2013-2015 Intel Corporation.
 
SPDX-License-Identifier: BSD-2-Clause-Patent
 
 
**/
 
//
// Include common header file for this module.
//
#include "CommonHeader.h"
 
#include "QNCSmmHelpers.h"
 
CONST QNC_SMM_SOURCE_DESC SX_SOURCE_DESC = {
  QNC_SMM_NO_FLAGS,
  {
    {
      {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIE}}, S_QNC_GPE0BLK_SMIE, N_QNC_GPE0BLK_SMIE_SLP
    },
    NULL_BIT_DESC_INITIALIZER
  },
  {
    {
      {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIS}}, S_QNC_GPE0BLK_SMIS, N_QNC_GPE0BLK_SMIS_SLP
    }
  }
};
 
VOID
SxGetContext(
  IN  DATABASE_RECORD    *Record,
  OUT QNC_SMM_CONTEXT    *Context
  )
{
  UINT32        Pm1Cnt;
 
  Pm1Cnt = IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
 
  //
  // By design, the context phase will always be ENTRY
  //
  Context->Sx.Phase = SxEntry;
 
  //
  // Map the PM1_CNT register's SLP_TYP bits to the context type
  //
  switch (Pm1Cnt & B_QNC_PM1BLK_PM1C_SLPTP) {
 
  case V_S0:
    Context->Sx.Type = SxS0;
    break;
 
  case V_S3:
    Context->Sx.Type = SxS3;
    break;
 
  case V_S4:
    Context->Sx.Type = SxS4;
    break;
 
  case V_S5:
    Context->Sx.Type = SxS5;
    break;
 
  default:
    ASSERT (FALSE);
    break;
  };
}
 
BOOLEAN
SxCmpContext (
  IN QNC_SMM_CONTEXT     *Context1,
  IN QNC_SMM_CONTEXT     *Context2
  )
{
  return (BOOLEAN)(Context1->Sx.Type == Context2->Sx.Type);
}
 
VOID
QNCSmmSxGoToSleep(
  VOID
  )
/*++
 
Routine Description:
 
  When we get an SMI that indicates that we are transitioning to a sleep state,
  we need to actually transition to that state.  We do this by disabling the
  "SMI on sleep enable" feature, which generates an SMI when the operating system
  tries to put the system to sleep, and then physically putting the system to sleep.
 
Returns:
 
  None.
 
--*/
{
  UINT32        Pm1Cnt;
 
  //
  // Flush cache into memory before we go to sleep. It is necessary for S3 sleep
  // because we may update memory in SMM Sx sleep handlers -- the updates are in cache now
  //
  AsmWbinvd();
 
  //
  // Disable SMIs
  //
  QNCSmmClearSource (&SX_SOURCE_DESC );
  QNCSmmDisableSource (&SX_SOURCE_DESC);
 
  //
  // Clear Sleep Type Enable
  //
  IoAnd16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIE, (UINT16)(~B_QNC_GPE0BLK_SMIE_SLP));
 
  // clear sleep SMI status
  IoAnd16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS, (UINT16)(S_QNC_GPE0BLK_SMIS));
 
  //
  // Now that SMIs are disabled, write to the SLP_EN bit again to trigger the sleep
  //
  Pm1Cnt = IoOr32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, B_QNC_PM1BLK_PM1C_SLPEN);
 
  //
  // The system just went to sleep. If the sleep state was S1, then code execution will resume
  // here when the system wakes up.
  //
  Pm1Cnt = IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
  if ((Pm1Cnt & B_QNC_PM1BLK_PM1C_SCIEN) == 0) {
    //
    // An ACPI OS isn't present, clear the sleep information
    //
    Pm1Cnt &= ~B_QNC_PM1BLK_PM1C_SLPTP;
    Pm1Cnt |= V_S0;
 
    IoWrite32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, Pm1Cnt);
  }
 
  QNCSmmClearSource (&SX_SOURCE_DESC);
  QNCSmmEnableSource (&SX_SOURCE_DESC);
}