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
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
/** @file
  Platform Clocks Lib file
 
  @copyright
  Copyright 1999 - 2021 Intel Corporation. <BR>
 
  SPDX-License-Identifier: BSD-2-Clause-Patent
**/
 
#include <Base.h>
#include <Library/IoLib.h>
#include <Library/PlatformClocksLib.h>
#include <Ppi/Smbus2.h>
#include <Ppi/SmbusPolicy.h>
#include <Library/DebugLib.h>
#include <Ppi/Stall.h>
#include <Library/HobLib.h>
#include <Platform.h>
#include <Library/BaseMemoryLib.h>
 
#define MAX_SMBUS_RETRIES        10
 
 
EFI_STATUS
ConfigureClockGeneratorOnSecondarySmbus (
  IN    EFI_PEI_SERVICES          **PeiServices,
  IN    EFI_PEI_SMBUS2_PPI        *SmbusPpi,
  IN    UINT8                     ClockAddress,
  IN    UINTN                     ConfigurationTableLength,
  IN    BOOLEAN                   EnableSpreadSpectrum,
  IN    CLOCK_GENERATOR_DETAILS   *mSupportedClockGeneratorT,
  IN OUT UINT8                    *ConfigurationTable
  );
 
/**
 
  Configure the clock generator using the SMBUS PPI services.
 
  This function performs a block write, and dumps debug information.
 
  @param PeiServices               - General purpose services available to every PEIM.
  @param ClockType                 - Clock generator's model name.
  @param ClockAddress              - SMBUS address of clock generator.
  @param ConfigurationTableLength  - Length of configuration table.
  @param ConfigurationTable        - Pointer of configuration table.
 
  @retval EFI_SUCCESS - Operation success.
 
**/
EFI_STATUS
ConfigureClockGenerator (
  IN EFI_PEI_SERVICES             **PeiServices,
  IN     CLOCK_GENERATOR_TYPE     ClockType,
  IN     UINT8                    ClockAddress,
  IN     UINTN                    ConfigurationTableLength,
  IN OUT UINT8                    *ConfigurationTable,
  IN     BOOLEAN                  EnableSpreadSpectrum,
  IN     CLOCK_GENERATOR_DETAILS  *mSupportedClockGeneratorT,
  IN     UINT8                    SecondarySmbus
  )
{
  EFI_STATUS                      Status;
  EFI_SMBUS_DEVICE_ADDRESS        SlaveAddress;
  UINT8                           Buffer[MAX_CLOCK_GENERATOR_BUFFER_LENGTH];
  UINTN                           Length;
  EFI_SMBUS_DEVICE_COMMAND        Command;
  EFI_PEI_SMBUS2_PPI              *SmbusPpi;
  UINT8                           SmbErrorsCounter;
 
  //
  // Locate SmBus Ppi
  //
  Status = (**PeiServices).LocatePpi (
                            PeiServices,
                            &gEfiPeiSmbus2PpiGuid,
                            0,
                            NULL,
                            &SmbusPpi
                            );
  ASSERT_EFI_ERROR (Status);
 
  //
  // Verify input arguments
  //
  ASSERT (ConfigurationTableLength >= 8);
  ASSERT (ConfigurationTableLength <= MAX_CLOCK_GENERATOR_BUFFER_LENGTH);
  ASSERT (ClockType < ClockGeneratorMax);
  ASSERT (ConfigurationTable != NULL);
 
  //
  // Init some local vars
  //
  SlaveAddress.SmbusDeviceAddress = ClockAddress >> 1;
  Length = sizeof (Buffer);
  Command = 0;
 
  if (SecondarySmbus == TRUE) {
 
    return (ConfigureClockGeneratorOnSecondarySmbus(PeiServices,
                                          SmbusPpi,
                                          ClockAddress,
                                          ConfigurationTableLength,
                                          EnableSpreadSpectrum,
                                          mSupportedClockGeneratorT,
                                          ConfigurationTable
                                         ));
  } else {
    //
    // Not LightningRidge
    // Read the clock generator on the primary SMBus
    //
 
    SmbErrorsCounter = 0;
 
    do
    {
    Status = SmbusPpi->Execute (
      SmbusPpi,
      SlaveAddress,
      Command,
      EfiSmbusReadBlock,
      FALSE,
      &Length,
      Buffer
      );
      if(Status != EFI_SUCCESS)
      {
        DEBUG ((EFI_D_ERROR, "SMBUS reading error\n"));
 
      }
 
      SmbErrorsCounter ++;
    }
    while ((Status != EFI_SUCCESS) && (SmbErrorsCounter < MAX_SMBUS_RETRIES));
 
    //
    // Sanity check that the requested clock type is present in our supported clocks table
    //
    DEBUG ((DEBUG_INFO, "Expected Clock Generator ID is %x, populated %x\n", mSupportedClockGeneratorT->ClockId, Buffer[7]));
 
    if (EnableSpreadSpectrum) {
      Buffer[mSupportedClockGeneratorT->SpreadSpectrumByteOffset] |= mSupportedClockGeneratorT->SpreadSpectrumBitOffset;
 
      if (ClockType == ClockGeneratorCk420) {
 
        // Ensure that the clock chip is operating in normal mode.
        //
        Buffer[10] &= ~BIT7;
      }
    } else {
      Buffer[mSupportedClockGeneratorT->SpreadSpectrumByteOffset] &= ~(mSupportedClockGeneratorT->SpreadSpectrumBitOffset);
    }
 
#ifdef EFI_DEBUG
    {
      UINT8   i;
      DEBUG ((DEBUG_INFO, "SlaveAddress.SmbusDeviceAddress %x: Size =%x\n", SlaveAddress.SmbusDeviceAddress, Length));
      for (i = 0; i < ConfigurationTableLength; i++) {
        DEBUG ((DEBUG_INFO, "Default Clock Generator Byte %d: %x\n", i, Buffer[i]));
      }
    }
#endif
 
    //
    // Program clock generator, using the platform default values
    //
 
  SmbErrorsCounter = 0;
  do
  {
    Command = 0;
    Status = SmbusPpi->Execute (
      SmbusPpi,
      SlaveAddress,
      Command,
      EfiSmbusWriteBlock,
      FALSE,
      &Length,  // &ConfigurationTableLength,
      Buffer   //ConfigurationTable
      );
   // ASSERT_EFI_ERROR (Status);
 
 
     if(Status != EFI_SUCCESS)
     {
       DEBUG ((EFI_D_ERROR, "SMBUS writing error\n"));
     }
 
     SmbErrorsCounter ++;
   }
   while ((Status != EFI_SUCCESS) && (SmbErrorsCounter < MAX_SMBUS_RETRIES));
 
    //
    // Dump contents after write
    //
#ifdef EFI_DEBUG
    {
      UINT8   i;
    SlaveAddress.SmbusDeviceAddress = ClockAddress >> 1;
    Length = sizeof (Buffer);
    Command = 0;
    Status =  SmbusPpi->Execute (
        SmbusPpi,
        SlaveAddress,
        Command,
        EfiSmbusReadBlock,
        FALSE,
        &Length,
        Buffer
        );
 
      for (i = 0; i < ConfigurationTableLength; i++) {
        DEBUG ((DEBUG_INFO, "Clock Generator Byte %d: %x\n", i, Buffer[i]));
      }
    }
#endif
 
    return EFI_SUCCESS;
  } // else (<not Kahuna>)
}
 
 
/**
 
  Configure clock generator on Kahuna
  Clock gen is on a secondary SMBus
 
  @param IN EFI_PEI_SERVICES         **PeiServices - Pointer to PEI Services table
  @param IN EFI_PEI_SMBUS2_PPI       *SmbusPpi - Pointer to SMBUs services PPI
  @param IN UINT8                    ClockAddress - SMBus address of clock gen
  @param IN UINT8                    *Buffer - Pointer to buffer containing byte stream to send to clock gen
  @param IN UINTN                    Length - Number of bytes in buffer
 
  @retval EFI_SUCCESS    The function completed successfully.
  @retval EFI_INVALID_PARAMETER     The function cannot continue due to length is out of bound.
 
**/
EFI_STATUS
ConfigureClockGeneratorOnSecondarySmbus (
  IN EFI_PEI_SERVICES         **PeiServices,
  IN EFI_PEI_SMBUS2_PPI       *SmbusPpi,
  IN UINT8                    ClockAddress,
  IN UINTN                    ConfigurationTableLength,
  IN BOOLEAN                  EnableSpreadSpectrum,
  IN CLOCK_GENERATOR_DETAILS  *mSupportedClockGeneratorT,
  IN OUT UINT8                *ConfigurationTable
  )
{
  EFI_PEI_STALL_PPI           *StallPpi;
  EFI_STATUS                  Status;
  EFI_SMBUS_DEVICE_ADDRESS    SlaveAddress;
  EFI_SMBUS_DEVICE_COMMAND    SmbusCommand;
  UINTN                       SmbusLength;
  UINT8                       SmbusData[MAX_CLOCK_GENERATOR_BUFFER_LENGTH];
  UINT8                       Buffer[MAX_CLOCK_GENERATOR_BUFFER_LENGTH];
  UINT8                       Length;
 
  ZeroMem (Buffer, sizeof(Buffer));
 
  if (ConfigurationTableLength > MAX_CLOCK_GENERATOR_BUFFER_LENGTH) {
    return EFI_INVALID_PARAMETER;
  }
 
  //
  // Locate Stall PPI
  //
  Status = (**PeiServices).LocatePpi (
                            PeiServices,
                            &gEfiPeiStallPpiGuid,
                            0,
                            NULL,
                            &StallPpi
                            );
  ASSERT_EFI_ERROR (Status);
 
  //
  // Get length of payload to send to clock gen
  //
  Length = (UINT8) ConfigurationTableLength;
 
  //
  // Copy the default clock generator data into Buffer
  //
  CopyMem ((VOID*)Buffer, ConfigurationTable, Length);
 
  //
  // Set spread spectrum bit in Buffer or clear it?
  //
  if (EnableSpreadSpectrum) {
    Buffer[mSupportedClockGeneratorT->SpreadSpectrumByteOffset] |= mSupportedClockGeneratorT->SpreadSpectrumBitOffset;
 
    if (mSupportedClockGeneratorT->ClockType == ClockGeneratorCk420) {
 
      //
      // Ensure that the clock chip is operating in normal mode.
      //
      Buffer[10] &= ~BIT7;
    }
  } else {
    Buffer[mSupportedClockGeneratorT->SpreadSpectrumByteOffset] &= ~(mSupportedClockGeneratorT->SpreadSpectrumBitOffset);
  }
 
  //
  // Now encapsulate the data for a Write Block command to the clock gen
  //  as the payload in a Write Block command to the SMBus bridge
  //
  // Segment address = 0xF2, this becomes slave address
  // Slave address (clock gen) = ClockAddress, this becomes slave command
  //
  SlaveAddress.SmbusDeviceAddress = (0xF2 >> 1);
  SmbusCommand = ClockAddress;
 
  //
  // Set byte index in clock gen to start with, always 0
  //
  SmbusData[0] = 0;
 
  //
  // Set byte count clock gen wants to see
  //
  SmbusData[1] = (UINT8) Length;
 
  //
  // Payload byte count for SMBus bridge
  //
  SmbusLength = Length + 2;
  if (SmbusLength > MAX_CLOCK_GENERATOR_BUFFER_LENGTH) {
    return EFI_INVALID_PARAMETER;
  }
 
  //
  // Copy the clock gen data to the SMBus buffer
  //
  CopyMem ((VOID *)(((UINT8*)SmbusData) + 2), (VOID *)Buffer, Length);
 
  //
  // Use EfiSmbusWriteBlock to communicate with clock gen
  //
  Status = SmbusPpi->Execute( SmbusPpi,
                              SlaveAddress,
                              SmbusCommand,
                              EfiSmbusWriteBlock,
                              FALSE,
                              &SmbusLength,
                              &SmbusData );
  return Status;
}