summaryrefslogtreecommitdiff
path: root/cpu/amd/geode_lx/gplvsa_ii/sysmgr/mdd.c
blob: 8a7cdf4d24daee46cd53ff2843e657b96e9fbe77 (plain)
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
/*
* Copyright (c) 2006-2008 Advanced Micro Devices,Inc. ("AMD").
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.

* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA 
*/

//******************************************************************************
//*    Routines related to the MBus Diverse Device 
//******************************************************************************


#include "VSA2.H"
#include "SYSMGR.H"
#include "GX2.H"
#include "MDD.H"
#include "PROTOS.H"
#include "DESCR.H"
#include "ACPI.H"
#include "VPCI.H"
#include "PCI.H"
#include "ACPI.H"
#include "CHIPSET.H"

#define A20_EN	 (A20_P_EN | A20_K_EN)
#define INIT_EN  (INIT_K_EN | INIT_P_EN)


// External function prototypes:
void Init_MFGPT(void);
UCHAR pascal ACPI_Trapping(USHORT);

// Local function prototypes:
void pascal Control_MDD_SMI(USHORT, ULONG);


// Local variables:
ULONG MDD_Base;

// External variables:
extern PCI_HEADER_ENTRY ISA_Hdr[];
extern Hardware HardwareInfo;


//***********************************************************************
// Enables/disables KEL SMIs
//***********************************************************************
void pascal Control_KEL_SMI(USHORT EnableFlag)
{
  Control_MDD_SMI(EnableFlag, KEL_ASMI_EN);
}

//***********************************************************************
// Enable/disable keyboard command snooping by KEL
//***********************************************************************
void pascal Control_KEL_Snoop(USHORT EnableFlag)
{ ULONG MsrAddr, MsrData;

  MsrAddr = MDD_Base;
  (USHORT)MsrAddr = MSR_KEL_CNTRL;
  MsrData = Read_MSR_LO(MsrAddr);

  if (EnableFlag) {
    MsrData |=  KEL_SNOOP;
  } else {
    MsrData &= ~KEL_SNOOP;
  }
  Write_MSR_LO(MsrAddr, MsrData);

}

//***********************************************************************
// Initializes the MBus Diverse Device
//***********************************************************************
void Init_MDD(void)
{ ULONG MsrAddr;
  USHORT ACPI_Bar;
  UCHAR i;


  // Find address of MBus Diverse Device
  MsrAddr = MDD_Base = Find_MBus_ID(ID_MDD, 1) & 0xFFFF0000;

  //*********************************************
  // Record MDD's LBARs in MSRs[]
  //*********************************************
  for (i = MSR_LBAR_IRQ; i <= MSR_LBAR_FLSH3; i++) {

    (UCHAR)MsrAddr = i;

    if (Init_Descr(MDD_LBAR, MsrAddr)) {
      break;
    }
  }

  // Clear PM1_STS
  (UCHAR)MsrAddr = ISA_Hdr[BAR5/4].LBar;
  ACPI_Bar = (USHORT)Read_MSR_LO(MsrAddr);
  out_16(ACPI_Bar, in_16(ACPI_Bar));


  // Initialize KEL

  // Enable keyboard snooping by KEL
  Control_KEL_Snoop(1);

  // Enable SMIs from:
  // - A20 & Init (keyboard and port 92h)
  // - KEL
  // - Extended PIC Mapper
  Control_MDD_SMI(1, A20_EN | INIT_EN | PIC_ASMI_EN | KEL_ASMI_EN);


  // Initialize the MFGPT
  Init_MFGPT();

  // Clear any pending PIC events
  (USHORT)MsrAddr = MBD_MSR_SMI;
  Write_MSR_HI(MsrAddr, PIC_ASMI_EN);

}




//***********************************************************************
// Implements CS5536's F0 Special Cycles.
// Linked to MDD's MSR_LEG_IO[31].
//
// When set, a Shutdown special cycle causes a reset. When the Special
// Cycles bit is cleared, a Shutdown special cycle is ignored.  Before 
// updating MSR_LEG_IO,  VSA will check MSR_ERR[15] and MSR_SMI[1]. If 
// either of these MSR bits are set, then no action is taken.  It will
// be assumed that a debugger is in use and VSA will not interfere.
//***********************************************************************
void pascal Update_Special_Cycles(USHORT EnableFlag)
{ ULONG MSR_Addr, MSR_Data;


  // If either MSR_ERR[15] and MSR_SMI[1] is set, then bail.
  if (Read_MSR_LO(MDD_Base + MBD_MSR_SMI) & 2) {
    return;
  }
  if (Read_MSR_LO(MDD_Base + MBD_MSR_ERROR) & 0x8000) {
    return;
  }

  // Link MSR_LEG_IO[RESET_SHUT_EN] to COMMAND[3]
  MSR_Addr = MDD_Base + MSR_LEG_IO;
  MSR_Data = Read_MSR_LO(MSR_Addr);

  if (EnableFlag) {
    MSR_Data |=  RESET_SHUT_EN;
  } else {
    MSR_Data &= ~RESET_SHUT_EN;
  }

  Write_MSR_LO(MSR_Addr, MSR_Data);
}


//***********************************************************************
// Enable/disable of MDD ASMI(s)
//***********************************************************************
void pascal Control_MDD_SMI(USHORT EnableFlag, ULONG EnableMask)
{ ULONG MsrAddr, MsrData;

  MsrAddr = MDD_Base;
  (USHORT)MsrAddr = MBD_MSR_SMI;

  MsrData = Read_MSR_LO(MsrAddr);
  if (EnableFlag) {
    MsrData |=  EnableMask;
   } else {
    MsrData &= ~EnableMask;
  }
  Write_MSR_LO(MsrAddr, MsrData);
}


//***********************************************************************
// Clears the ACPI Status register
// This routine fills in MsgPacket[0] = ACPI GPE0_STS
// and MsgPacket[1] bits[15:0] = ACPI PM1_STS
//***********************************************************************
USHORT Get_ACPI_Status(ULONG *msgp)
{ USHORT ACPI_Bar, PM1_Status;
  ULONG GPE_Status;
  UCHAR Flag;

  // Disable ACPI trapping
  Flag = ACPI_Trapping(0);

  // Get ACPI Status
  ACPI_Bar = ISA_Hdr[BAR5/4].Value_LO;

  (UCHAR)ACPI_Bar = GPE0_STS_OFS;
  GPE_Status = in_32(ACPI_Bar);

  // Don't clear PIC status
  GPE_Status &= ~1;


  msgp[1] = GPE_Status;


  (UCHAR)ACPI_Bar = PM1_STS_OFS;
  PM1_Status = in_16(ACPI_Bar);


  // Enable ACPI trapping
  if (Flag) {
    ACPI_Trapping(1);
  }

  msgp[2] = (ULONG)PM1_Status;

  return (PM1_Status || GPE_Status);
}

//***********************************************************************
// Enable PM logic
//***********************************************************************
void Enable_PME_Event(UCHAR EnableFlag, UCHAR Pm1Bit, UCHAR PmeBit, USHORT Attributes)
{ ULONG Gpe, Pm1, bmGPE0;
  USHORT ACPI_Bar, bmPM1;
  UCHAR Flag;
  static UCHAR pme_instance = 0;
  static UCHAR PM1_Instance[11] = {0,0,0,0,0,0,0,0,0,0,0};
  static UCHAR PME_Instance[8]  = {0,0,0,0,0,0,0,0};
  static ULONG GPE0_Masks[] = { // Maps PME # to GPE0 bits
    0x00010000,
    0x00020000,
    0x00040000,
    0x00080000,
    0x00100000,
    0x00200000,
    0x40000000,
    0x80000000,
  };

  bmPM1 = 0;
  bmGPE0 = 0L;
  if (Attributes & PM1) {
    bmPM1 = 1 << Pm1Bit;

    if (EnableFlag) {
      PM1_Instance[Pm1Bit]++;
	} else {
      if (PM1_Instance[Pm1Bit]) {
        // If there are still registrations for this PM1 bit...
        if (--PM1_Instance[Pm1Bit]) {
          // then don't turn disable it
          return;
        }
      } else {
        // Error: 
        return;
      }
    }
  }
  if (Attributes & GPE) {
    bmGPE0 = GPE0_Masks[PmeBit];
    if (EnableFlag) {
      PME_Instance[PmeBit]++;
	} else {
      if (PME_Instance[PmeBit]) {
        // If there are still registrations for this GEP0 bit...
        if (--PME_Instance[PmeBit]) {
          // then don't turn disable it
          return;
        }
      } else {
        // Error: 
        return;
      }
    }
  }


  if (!(Attributes & NO_ASMI)) {
    // Keep a count of PME events.
    // Once all have been de-registered, turn off PM_ASMI bit.
    if (EnableFlag) {
      if (Attributes & PME) {
        pme_instance++;
      }
      // Enable ASMIs from Power Management logic
      Control_MDD_SMI(EnableFlag, PM_ASMI_EN);
    } else {
      if (Attributes & PME) {
        if (pme_instance != 0) {
          if (--pme_instance == 0) {
            // Disable ASMIs from Power Management logic
            Control_MDD_SMI(0, PM_ASMI_EN);
          }
        }
      }
    }
  }

  // See if we want to enable the approriate bits in PM1_EN and GPE0_EN
  // if set to NO_ENALE we don't enable (Used by ACPI as the OS controls)
  if (!(Attributes & NO_ENABLE)) {
    // Disable ACPI trapping
    Flag = ACPI_Trapping(0);

    // Get ACPI base address
    ACPI_Bar = ISA_Hdr[BAR5/4].Value_LO;

    if (bmPM1) {
      // Must do 32-bit I/O to avoid shadow register bug (IAeng00003062)
      (UCHAR)ACPI_Bar = 0x00;
      Pm1 = in_32(ACPI_Bar);
      if (EnableFlag) {
        Pm1 |=   (ULONG)bmPM1 << 16;
      } else {
        Pm1 &= ~((ULONG)bmPM1 << 16);
      }
      out_32(ACPI_Bar, Pm1);

      // Serialize the previous I/O write
      in_16(ACPI_Bar);

      // Clear spurious status
      (UCHAR)ACPI_Bar = PM1_STS_OFS;
      out_32(ACPI_Bar, (ULONG)Pm1);
    }

    if (bmGPE0) {
      (UCHAR)ACPI_Bar = GPE0_EN_OFS;
      Gpe = in_32(ACPI_Bar);
      if (EnableFlag) {
        Gpe |=  bmGPE0;
      } else {
        Gpe &= ~bmGPE0;
      }
      out_32(ACPI_Bar, Gpe);
      // Serialize the previous I/O write
      in_32(ACPI_Bar);

      // Clear spurious status
      (UCHAR)ACPI_Bar = GPE0_STS_OFS;
      out_32(ACPI_Bar, Gpe);
    }

    // Serialize the previous I/O write
    in_32(ACPI_Bar);
  
    // Re-enable ACPI trapping
    if (Flag) {
      ACPI_Trapping(1);
    }
  }
}