1 /** @file
2   Platform Hook Library instances
3 
4 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include <Base.h>
10 #include <Uefi/UefiBaseType.h>
11 #include <Library/PlatformHookLib.h>
12 #include <Library/BaseLib.h>
13 #include <Library/IoLib.h>
14 #include <Library/PciLib.h>
15 #include <Library/PcdLib.h>
16 #include <SystemAgent/Include/SaAccess.h>
17 #include <SioRegs.h>
18 #include <Library/MmPciLib.h>
19 #include <Library/PchCycleDecodingLib.h>
20 #include <Register/PchRegsLpc.h>
21 #include <PchAccess.h>
22 
23 #define COM1_BASE                                 0x3f8
24 #define COM2_BASE                                 0x2f8
25 
26 #define SIO_DOCKING_LPC_SWITCH_REGISTER_ADDRESS   0x0690
27 
28 #define LPC_SIO_INDEX_DEFAULT_PORT_2              0x2E
29 #define LPC_SIO_DATA_DEFAULT_PORT_2               0x2F
30 #define LPC_SIO_GPIO_REGISTER_ADDRESS_2           0x0A20
31 
32 #define LEGACY_DAUGHTER_CARD_SIO_INDEX_PORT       0x2E
33 #define LEGACY_DAUGHTER_CARD_SIO_DATA_PORT        0x2F
34 #define LEGACY_DAUGHTER_CARD_2_SIO_INDEX_PORT     0x4E
35 #define LEGACY_DAUGHTER_CARD_2_SIO_DATA_PORT      0x4F
36 
37 typedef struct {
38   UINT8 Register;
39   UINT8 Value;
40 } EFI_SIO_TABLE;
41 
42 GLOBAL_REMOVE_IF_UNREFERENCED EFI_SIO_TABLE mSioTable[] = {
43   {0x002, 0x88},     // Power On UARTs
44   {0x024, COM1_BASE >> 2},
45   {0x025, COM2_BASE >> 2},
46   {0x028, 0x043},    // IRQ of UARTs, UART2 IRQ=3,UART1 IRQ=4,
47   {0x029, 0x080},    // SIRQ_CLKRUN_EN
48   {0x02A, 0x000},
49   {0x02B, 0x0DE},
50   {0x00A, 0x040},
51   {0x00C, 0x00E},
52   {0x02c, 0x002},
53   {0x030, FixedPcdGet16 (PcdSioBaseAddress) >> 4},
54   {0x03b, SIO_DOCKING_LPC_SWITCH_REGISTER_ADDRESS >> 8},
55   {0x03c, SIO_DOCKING_LPC_SWITCH_REGISTER_ADDRESS & 0xff},
56   {0x03a, 0x00A},    // LPC Docking Enabling
57   {0x031, 0x01f},
58   {0x032, 0x000},
59   {0x033, 0x004},
60   {0x038, 0x0FB},
61   {0x035, 0x0FE},
62   {0x036, 0x000},
63   {0x037, 0x0FF},
64   {0x039, 0x000},
65   {0x034, 0x001},
66   {0x012, FixedPcdGet16 (PcdLpcSioConfigDefaultPort) & 0xFF},           // Relocate configuration ports base address
67   {0x013, (FixedPcdGet16 (PcdLpcSioConfigDefaultPort) >> 8) & 0xFF}     // to ensure SIO config address can be accessed in OS
68 };
69 
70 GLOBAL_REMOVE_IF_UNREFERENCED EFI_SIO_TABLE mSioTableSmsc1000[] = {
71   {0x002, 0x88},     // Power On UARTs
72   {0x007, 0x00},
73   {0x024, COM1_BASE >> 2},
74   {0x025, COM2_BASE >> 2},
75   {0x028, 0x043},    // IRQ of UARTs, UART2 IRQ=3,UART1 IRQ=4,
76   {0x029, 0x080},    // SIRQ_CLKRUN_EN
77   {0x02A, 0x000},
78   {0x02B, 0x0DE},
79   {0x00A, 0x040},
80   {0x00C, 0x00E},
81   {0x030, FixedPcdGet16 (PcdSioBaseAddress) >> 4},
82   {0x03b, SIO_DOCKING_LPC_SWITCH_REGISTER_ADDRESS >> 8},
83   {0x03c, SIO_DOCKING_LPC_SWITCH_REGISTER_ADDRESS & 0xff},
84   {0x03a, 0x00A},    // LPC Docking Enabling
85   {0x031, 0x01f},
86   {0x032, 0x000},
87   {0x033, 0x004},
88   {0x038, 0x0FB},
89   {0x035, 0x0FE},
90   {0x036, 0x000},
91   {0x037, 0x0FE},
92   {0x039, 0x000},
93   {0x034, 0x001}
94 };
95 
96 GLOBAL_REMOVE_IF_UNREFERENCED EFI_SIO_TABLE mSioTableWpcn381u[] = {
97   {0x29, 0x0A0},                  // Enable super I/O clock and set to 48MHz
98   {0x22, 0x003},                  //
99   {0x07, 0x003},                  // Select UART0 device
100   {0x60, (COM1_BASE >> 8)},       // Set Base Address MSB
101   {0x61, (COM1_BASE & 0x00FF)},   // Set Base Address LSB
102   {0x70, 0x004},                  // Set to IRQ4
103   {0x30, 0x001},                  // Enable it with Activation bit
104   {0x07, 0x002},                  // Select UART1 device
105   {0x60, (COM2_BASE >> 8)},       // Set Base Address MSB
106   {0x61, (COM2_BASE & 0x00FF)},   // Set Base Address LSB
107   {0x70, 0x003},                  // Set to IRQ3
108   {0x30, 0x001},                  // Enable it with Activation bit
109   {0x07, 0x007},                  // Select GPIO device
110   {0x60, (LPC_SIO_GPIO_REGISTER_ADDRESS_2 >> 8)},      // Set Base Address MSB
111   {0x61, (LPC_SIO_GPIO_REGISTER_ADDRESS_2 & 0x00FF)},  // Set Base Address LSB
112   {0x30, 0x001},                  // Enable it with Activation bit
113   {0x21, 0x001},                  // Global Device Enable
114   {0x26, 0x000}                   // Fast Enable UART 0 & 1 as their enable & activation bit
115 };
116 
117 //
118 // National PC8374L
119 //
120 GLOBAL_REMOVE_IF_UNREFERENCED EFI_SIO_TABLE mDesktopSioTable[] = {
121   {0x007, 0x03}, // Select Com1
122   {0x061, 0xF8}, // 0x3F8
123   {0x060, 0x03}, // 0x3F8
124   {0x070, 0x04}, // IRQ4
125   {0x030, 0x01}  // Active
126 };
127 
128 //
129 // IT8628
130 //
131 GLOBAL_REMOVE_IF_UNREFERENCED EFI_SIO_TABLE mSioIt8628TableSerialPort[] = {
132   {0x023, 0x09}, // Clock Selection register
133   {0x007, 0x01}, // Com1 Logical Device Number select
134   {0x061, 0xF8}, // Serial Port 1 Base Address MSB Register
135   {0x060, 0x03}, // Serial Port 1 Base Address LSB Register
136   {0x070, 0x04}, // Serial Port 1 Interrupt Level Select
137   {0x030, 0x01}, // Serial Port 1 Activate
138   {0x007, 0x02}, // Com1 Logical Device Number select
139   {0x061, 0xF8}, // Serial Port 2 Base Address MSB Register
140   {0x060, 0x02}, // Serial Port 2 Base Address MSB Register
141   {0x070, 0x03}, // Serial Port 2 Interrupt Level Select
142   {0x030, 0x01}  // Serial Port 2 Activate
143 };
144 
145 GLOBAL_REMOVE_IF_UNREFERENCED EFI_SIO_TABLE mSioIt8628TableParallelPort[] = {
146   {0x007, 0x03}, // Parallel Port Logical Device Number select
147   {0x030, 0x00}, // Parallel port Activate
148   {0x061, 0x78}, // Parallel Port Base Address 1 MSB Register
149   {0x060, 0x03}, // Parallel Port Base Address 1 LSB Register
150   {0x063, 0x78}, // Parallel Port Base Address 2 MSB Register
151   {0x062, 0x07}, // Parallel Port Base Address 1 LSB Register
152   {0x0F0, 0x03}  // Special Configuration register
153 };
154 
155 
156 GLOBAL_REMOVE_IF_UNREFERENCED EFI_SIO_TABLE mSioTableWinbondX374[] = {
157   {0x07, 0x03},                   // Select UART0 device
158   {0x60, (COM1_BASE >> 8)},       // Set Base Address MSB
159   {0x61, (COM1_BASE & 0x00FF)},   // Set Base Address LSB
160   {0x70, 0x04},                   // Set to IRQ4
161   {0x30, 0x01}                    // Enable it with Activation bit
162 };
163 
164 GLOBAL_REMOVE_IF_UNREFERENCED EFI_SIO_TABLE mSioTablePilot3[] = {
165   {0x07, 0x02}, // Set logical device SP Serial port Com0
166   {0x61, 0xF8}, // Write Base Address LSB register 0x3F8
167   {0x60, 0x03}, // Write Base Address MSB register 0x3F8
168   {0x70, 0x04}, // Write IRQ1 value (IRQ 1)  keyboard
169   {0x30, 0x01}  // Enable serial port with Activation bit
170 };
171 
172 /**
173   Detect if a National 393 SIO is docked. If yes, enable the docked SIO
174   and its serial port, and disable the onboard serial port.
175 
176   @retval EFI_SUCCESS     Operations performed successfully.
177 **/
178 STATIC
179 VOID
180 CheckNationalSio (
181   VOID
182   )
183 {
184   UINT8           Data8;
185 
186   //
187   // Pc87393 access is through either (0x2e, 0x2f) or (0x4e, 0x4f).
188   // We use (0x2e, 0x2f) which is determined by BADD default strapping
189   //
190 
191   //
192   // Read the Pc87393 signature
193   //
194   IoWrite8 (0x2e, 0x20);
195   Data8 = IoRead8 (0x2f);
196 
197   if (Data8 == 0xea) {
198     //
199     // Signature matches - National PC87393 SIO is docked
200     //
201 
202     //
203     // Enlarge the LPC decode scope to accommodate the Docking LPC Switch
204     // Register (SIO_DOCKING_LPC_SWITCH_REGISTER_ADDRESS is allocated at
205     // SIO_BASE_ADDRESS + 0x10)
206     //
207     PchLpcGenIoRangeSet ((FixedPcdGet16 (PcdSioBaseAddress) & (UINT16)~0x7F), 0x20);
208 
209     //
210     // Enable port switch
211     //
212     IoWrite8 (SIO_DOCKING_LPC_SWITCH_REGISTER_ADDRESS, 0x06);
213 
214     //
215     // Turn on docking power
216     //
217     IoWrite8 (FixedPcdGet16 (PcdSioBaseAddress) + 0x0E, 0x8c);
218 
219     IoWrite8 (FixedPcdGet16 (PcdSioBaseAddress) + 0x0E, 0x9c);
220 
221     IoWrite8 (FixedPcdGet16 (PcdSioBaseAddress) + 0x0E, 0xBc);
222 
223     //
224     // Enable port switch
225     //
226     IoWrite8 (SIO_DOCKING_LPC_SWITCH_REGISTER_ADDRESS, 0x7);
227 
228     //
229     // GPIO setting
230     //
231     IoWrite8 (0x2e, 0x24);
232     IoWrite8 (0x2f, 0x29);
233 
234     //
235     // Enable chip clock
236     //
237     IoWrite8 (0x2e, 0x29);
238     IoWrite8 (0x2f, 0x1e);
239 
240 
241     //
242     // Enable serial port
243     //
244 
245     //
246     // Select com1
247     //
248     IoWrite8 (0x2e, 0x7);
249     IoWrite8 (0x2f, 0x3);
250 
251     //
252     // Base address: 0x3f8
253     //
254     IoWrite8 (0x2e, 0x60);
255     IoWrite8 (0x2f, 0x03);
256     IoWrite8 (0x2e, 0x61);
257     IoWrite8 (0x2f, 0xf8);
258 
259     //
260     // Interrupt: 4
261     //
262     IoWrite8 (0x2e, 0x70);
263     IoWrite8 (0x2f, 0x04);
264 
265     //
266     // Enable bank selection
267     //
268     IoWrite8 (0x2e, 0xf0);
269     IoWrite8 (0x2f, 0x82);
270 
271     //
272     // Activate
273     //
274     IoWrite8 (0x2e, 0x30);
275     IoWrite8 (0x2f, 0x01);
276 
277     //
278     // Disable onboard serial port
279     //
280     IoWrite8 (FixedPcdGet16 (PcdLpcSioConfigDefaultPort), 0x55);
281 
282     //
283     // Power Down UARTs
284     //
285     IoWrite8 (PcdGet16 (PcdLpcSioIndexPort), 0x2);
286     IoWrite8 (PcdGet16 (PcdLpcSioDataPort), 0x00);
287 
288     //
289     // Dissable COM1 decode
290     //
291     IoWrite8 (PcdGet16 (PcdLpcSioIndexPort), 0x24);
292     IoWrite8 (PcdGet16 (PcdLpcSioDataPort), 0);
293 
294     //
295     // Disable COM2 decode
296     //
297     IoWrite8 (PcdGet16 (PcdLpcSioIndexPort), 0x25);
298     IoWrite8 (PcdGet16 (PcdLpcSioDataPort), 0);
299 
300     //
301     // Disable interrupt
302     //
303     IoWrite8 (PcdGet16 (PcdLpcSioIndexPort), 0x28);
304     IoWrite8 (PcdGet16 (PcdLpcSioDataPort), 0x0);
305 
306     IoWrite8 (FixedPcdGet16 (PcdLpcSioConfigDefaultPort), 0xAA);
307 
308     //
309     // Enable floppy
310     //
311 
312     //
313     // Select floppy
314     //
315     IoWrite8 (0x2e, 0x7);
316     IoWrite8 (0x2f, 0x0);
317 
318     //
319     // Base address: 0x3f0
320     //
321     IoWrite8 (0x2e, 0x60);
322     IoWrite8 (0x2f, 0x03);
323     IoWrite8 (0x2e, 0x61);
324     IoWrite8 (0x2f, 0xf0);
325 
326     //
327     // Interrupt: 6
328     //
329     IoWrite8 (0x2e, 0x70);
330     IoWrite8 (0x2f, 0x06);
331 
332     //
333     // DMA 2
334     //
335     IoWrite8 (0x2e, 0x74);
336     IoWrite8 (0x2f, 0x02);
337 
338     //
339     // Activate
340     //
341     IoWrite8 (0x2e, 0x30);
342     IoWrite8 (0x2f, 0x01);
343 
344   } else {
345 
346     //
347     // No National pc87393 SIO is docked, turn off dock power and
348     // disable port switch
349     //
350     // IoWrite8 (SIO_BASE_ADDRESS + 0x0E, 0xbf);
351     // IoWrite8 (0x690, 0);
352 
353     //
354     // If no National pc87393, just return
355     //
356     return;
357   }
358 }
359 
360 
361 /**
362 Check whether the IT8628 SIO present on LPC. If yes, enable its serial
363 ports, parallel port, and port 80.
364 
365 @retval EFI_SUCCESS     Operations performed successfully.
366 **/
367 STATIC
368 VOID
369 It8628SioSerialPortInit (
370   VOID
371   )
372 {
373   UINT8   ChipId0              = 0;
374   UINT8   ChipId1              = 0;
375   UINT16  LpcIoDecondeRangeSet = 0;
376   UINT16  LpcIoDecoodeSet      = 0;
377   UINT8   Index;
378   UINTN   LpcBaseAddr;
379 
380 
381   //
382   // Enable I/O decoding for COM1 (3F8h-3FFh), COM2(2F8h-2FFh), I/O port 2Eh/2Fh.
383   //
384   LpcBaseAddr = MmPciBase (
385                   DEFAULT_PCI_BUS_NUMBER_PCH,
386                   PCI_DEVICE_NUMBER_PCH_LPC,
387                   PCI_FUNCTION_NUMBER_PCH_LPC
388                   );
389 
390   LpcIoDecondeRangeSet = (UINT16) MmioRead16 (LpcBaseAddr + R_PCH_LPC_IOD);
391   LpcIoDecoodeSet = (UINT16) MmioRead16 (LpcBaseAddr + R_PCH_LPC_IOE);
392   MmioWrite16 ((LpcBaseAddr + R_PCH_LPC_IOD), (LpcIoDecondeRangeSet | ((V_PCH_LPC_IOD_COMB_2F8 << 4) | V_PCH_LPC_IOD_COMA_3F8)));
393   MmioWrite16 ((LpcBaseAddr + R_PCH_LPC_IOE), (LpcIoDecoodeSet | (B_PCH_LPC_IOE_SE | B_PCH_LPC_IOE_CBE | B_PCH_LPC_IOE_CAE)));
394 
395   //
396   // Enter MB PnP Mode
397   //
398   IoWrite8 (LPC_SIO_INDEX_DEFAULT_PORT_2, 0x87);
399   IoWrite8 (LPC_SIO_INDEX_DEFAULT_PORT_2, 0x01);
400   IoWrite8 (LPC_SIO_INDEX_DEFAULT_PORT_2, 0x55);
401   IoWrite8 (LPC_SIO_INDEX_DEFAULT_PORT_2, 0x55);
402 
403   //
404   // Read Chip Id of SIO IT8628 (registers 0x20 and 0x21)
405   //
406   IoWrite8 (LPC_SIO_INDEX_DEFAULT_PORT_2, 0x20);
407   ChipId0 = IoRead8 (LPC_SIO_DATA_DEFAULT_PORT_2);
408 
409   IoWrite8 (LPC_SIO_INDEX_DEFAULT_PORT_2, 0x21);
410   ChipId1 = IoRead8 (LPC_SIO_DATA_DEFAULT_PORT_2);
411 
412   //
413   // Enable Serial Port 1, Port 2
414   //
415   if ((ChipId0 == 0x86) && (ChipId1 == 0x28)) {
416     for (Index = 0; Index < sizeof (mSioIt8628TableSerialPort) / sizeof (EFI_SIO_TABLE); Index++) {
417       IoWrite8 (LPC_SIO_INDEX_DEFAULT_PORT_2, mSioIt8628TableSerialPort[Index].Register);
418       IoWrite8 (LPC_SIO_DATA_DEFAULT_PORT_2, mSioIt8628TableSerialPort[Index].Value);
419     }
420   }
421 
422   //
423   // Exit MB PnP Mode
424   //
425   IoWrite8 (LPC_SIO_INDEX_DEFAULT_PORT_2, 0x02);
426   IoWrite8 (LPC_SIO_DATA_DEFAULT_PORT_2, 0x02);
427 
428   return;
429 }
430 
431 
432 /**
433   Performs platform specific initialization required for the CPU to access
434   the hardware associated with a SerialPortLib instance.  This function does
435   not initialize the serial port hardware itself.  Instead, it initializes
436   hardware devices that are required for the CPU to access the serial port
437   hardware.  This function may be called more than once.
438 
439   @retval RETURN_SUCCESS       The platform specific initialization succeeded.
440   @retval RETURN_DEVICE_ERROR  The platform specific initialization could not be completed.
441 
442 **/
443 RETURN_STATUS
444 EFIAPI
445 PlatformHookSerialPortInitialize (
446   VOID
447   )
448 {
449   UINT16  ConfigPort;
450   UINT16  IndexPort;
451   UINT16  DataPort;
452   UINT16  DeviceId;
453   UINT8   Index;
454   UINT16  AcpiBase;
455 
456   //
457   // Set the ICH ACPI Base Address (Reg#40h) and ACPI Enable bit
458   // in ACPI Controll (Reg#44h bit7) for PrePpiStall function use.
459   //
460   IndexPort = 0;
461   DataPort = 0;
462   Index = 0;
463   AcpiBase = 0;
464   PchAcpiBaseGet (&AcpiBase);
465   if (AcpiBase == 0) {
466     PchAcpiBaseSet (PcdGet16 (PcdAcpiBaseAddress));
467   }
468 
469   //
470   // Enable I/O decoding for COM1(3F8h-3FFh), COM2(2F8h-2FFh), I/O port 2Eh/2Fh, 4Eh/4Fh, 60h/64Fh and 62h/66h.
471   //
472   PchLpcIoDecodeRangesSet (PcdGet16 (PcdLpcIoDecodeRange));
473   PchLpcIoEnableDecodingSet (PcdGet16 (PchLpcIoEnableDecoding));
474 
475   // Configure Sio IT8628
476   It8628SioSerialPortInit ();
477 
478   DeviceId = MmioRead16 (MmPciBase (SA_MC_BUS, 0, 0) + R_SA_MC_DEVICE_ID);
479   if (IS_SA_DEVICE_ID_MOBILE (DeviceId)) {
480     //
481     // if no EC, it is SV Bidwell Bar board
482     //
483     if ((IoRead8 (0x66) != 0xFF) && (IoRead8 (0x62) != 0xFF)) {
484       //
485       // Super I/O initialization for SMSC SI1007
486       //
487       ConfigPort = FixedPcdGet16 (PcdLpcSioConfigDefaultPort);
488       DataPort   = PcdGet16 (PcdLpcSioDataDefaultPort);
489       IndexPort  = PcdGet16 (PcdLpcSioIndexDefaultPort);
490 
491       //
492       // 128 Byte Boundary and SIO Runtime Register Range is 0x0 to 0xF;
493       //
494       PchLpcGenIoRangeSet (FixedPcdGet16 (PcdSioBaseAddress) & (~0x7F), 0x10);
495 
496       //
497       // Program and Enable Default Super IO Configuration Port Addresses and range
498       //
499       PchLpcGenIoRangeSet (FixedPcdGet16 (PcdLpcSioConfigDefaultPort) & (~0xF), 0x10);
500 
501       //
502       // Enter Config Mode
503       //
504       IoWrite8 (ConfigPort, 0x55);
505 
506       //
507       // Check for SMSC SIO1007
508       //
509       IoWrite8 (IndexPort, 0x0D);   // SMSC SIO1007 Device ID register is 0x0D
510       if (IoRead8 (DataPort) == 0x20) {   // SMSC SIO1007 Device ID is 0x20
511         //
512         // Configure SIO
513         //
514         for (Index = 0; Index < sizeof (mSioTable) / sizeof (EFI_SIO_TABLE); Index++) {
515           IoWrite8 (IndexPort, mSioTable[Index].Register);
516           IoWrite8 (DataPort, mSioTable[Index].Value);
517         }
518 
519         //
520         // Exit Config Mode
521         //
522         IoWrite8 (FixedPcdGet16 (PcdLpcSioConfigDefaultPort), 0xAA);
523 
524         //
525         // GPIO 15-17:IN  10-14:OUT  Enable RS232  ref: Page42 of CRB_SCH
526         //
527         IoWrite8 (FixedPcdGet16 (PcdSioBaseAddress) + 0x0c, 0x1f);
528       }
529 
530       //
531       // Check if a National Pc87393 SIO is docked
532       //
533       CheckNationalSio ();
534 
535       //
536       // Super I/O initialization for SMSC SIO1000
537       //
538       ConfigPort = PcdGet16 (PcdLpcSioIndexPort);
539       IndexPort  = PcdGet16 (PcdLpcSioIndexPort);
540       DataPort   = PcdGet16 (PcdLpcSioDataPort);
541 
542       //
543       // Enter Config Mode
544       //
545       IoWrite8 (ConfigPort, 0x55);
546 
547       //
548       // Check for SMSC SIO1000
549       //
550       if (IoRead8 (ConfigPort) != 0xFF) {
551         //
552         // Configure SIO
553         //
554         for (Index = 0; Index < sizeof (mSioTableSmsc1000) / sizeof (EFI_SIO_TABLE); Index++) {
555           IoWrite8 (IndexPort, mSioTableSmsc1000[Index].Register);
556           IoWrite8 (DataPort, mSioTableSmsc1000[Index].Value);
557         }
558 
559         //
560         // Exit Config Mode
561         //
562         IoWrite8 (FixedPcdGet16 (PcdLpcSioConfigDefaultPort), 0xAA);
563       }
564 
565       //
566       // Super I/O initialization for Winbond WPCN381U
567       //
568       IndexPort  = LPC_SIO_INDEX_DEFAULT_PORT_2;
569       DataPort   = LPC_SIO_DATA_DEFAULT_PORT_2;
570 
571       //
572       // Check for Winbond WPCN381U
573       //
574       IoWrite8 (IndexPort, 0x20);         // Winbond WPCN381U Device ID register is 0x20
575       if (IoRead8 (DataPort) == 0xF4) {   // Winbond WPCN381U Device ID is 0xF4
576         //
577         // Configure SIO
578         //
579         for (Index = 0; Index < sizeof (mSioTableWpcn381u) / sizeof (EFI_SIO_TABLE); Index++) {
580           IoWrite8 (IndexPort, mSioTableWpcn381u[Index].Register);
581           IoWrite8 (DataPort, mSioTableWpcn381u[Index].Value);
582         }
583       }
584     } //EC is not exist, skip mobile board detection for SV board
585 
586     //
587     //add for SV Bidwell Bar board
588     //
589     if (IoRead8 (COM1_BASE) == 0xFF) {
590       //
591       // Super I/O initialization for Winbond WPCD374 (LDC2) and 8374 (LDC)
592       // Looking for LDC2 card first
593       //
594       IoWrite8 (LEGACY_DAUGHTER_CARD_2_SIO_INDEX_PORT, 0x55);
595       if (IoRead8 (LEGACY_DAUGHTER_CARD_2_SIO_INDEX_PORT) == 0x55) {
596         IndexPort = LEGACY_DAUGHTER_CARD_2_SIO_INDEX_PORT;
597         DataPort  = LEGACY_DAUGHTER_CARD_2_SIO_DATA_PORT;
598       } else {
599         IndexPort = LEGACY_DAUGHTER_CARD_SIO_INDEX_PORT;
600         DataPort  = LEGACY_DAUGHTER_CARD_SIO_DATA_PORT;
601       }
602 
603       IoWrite8 (IndexPort, 0x20);         // Winbond x374 Device ID register is 0x20
604       if (IoRead8 (DataPort) == 0xF1) {   // Winbond x374 Device ID is 0xF1
605         for (Index = 0; Index < sizeof (mSioTableWinbondX374) / sizeof (EFI_SIO_TABLE); Index++) {
606           IoWrite8 (IndexPort, mSioTableWinbondX374[Index].Register);
607           IoWrite8 (DataPort, mSioTableWinbondX374[Index].Value);
608         }
609       }
610     }// end of Bidwell Bar SIO initialization
611   } else if (IS_SA_DEVICE_ID_DESKTOP (DeviceId) ||  IS_SA_DEVICE_ID_SERVER (DeviceId)) {
612     //
613     // If we are in debug mode, we will allow serial status codes
614     //
615 
616     //
617     // National PC8374 SIO & Winbond WPCD374 (LDC2)
618     //
619     IndexPort  = LEGACY_DAUGHTER_CARD_2_SIO_INDEX_PORT;
620 
621     IoWrite8 (IndexPort, 0x55);
622     if (IoRead8 (IndexPort) == 0x55) {
623       IndexPort = LEGACY_DAUGHTER_CARD_2_SIO_INDEX_PORT;
624       DataPort  = LEGACY_DAUGHTER_CARD_2_SIO_DATA_PORT;
625     } else {
626       IndexPort = LEGACY_DAUGHTER_CARD_SIO_INDEX_PORT;
627       DataPort  = LEGACY_DAUGHTER_CARD_SIO_DATA_PORT;
628     }
629 
630     //
631     // Configure SIO
632     //
633     IoWrite8 (IndexPort, 0x20);         // Winbond x374 Device ID register is 0x20
634     if (IoRead8 (DataPort) == 0xF1) {   // Winbond x374 Device ID is 0xF1
635       for (Index = 0; Index < sizeof (mDesktopSioTable) / sizeof (EFI_SIO_TABLE); Index++) {
636         IoWrite8 (IndexPort, mDesktopSioTable[Index].Register);
637         //PrePpiStall (200);
638         IoWrite8 (DataPort, mDesktopSioTable[Index].Value);
639         //PrePpiStall (200);
640       }
641       return RETURN_SUCCESS;
642     }
643     //
644     // Configure Pilot3 SIO
645     //
646     IoWrite8 (PILOTIII_SIO_INDEX_PORT, PILOTIII_UNLOCK); //Enter config mode.
647     IoWrite8 (PILOTIII_SIO_INDEX_PORT, PILOTIII_CHIP_ID_REG);     // Pilot3 SIO Device ID register is 0x20.
648     if (IoRead8 (PILOTIII_SIO_DATA_PORT) == PILOTIII_CHIP_ID) {    // Pilot3 SIO Device ID register is 0x03.
649       //
650       // Configure SIO
651       //
652       for (Index = 0; Index < sizeof (mSioTablePilot3) / sizeof (EFI_SIO_TABLE); Index++) {
653         IoWrite8 (PILOTIII_SIO_INDEX_PORT, mSioTablePilot3[Index].Register);
654         IoWrite8 (PILOTIII_SIO_DATA_PORT, mSioTablePilot3[Index].Value);
655       }
656     }
657     IoWrite8 (PILOTIII_SIO_INDEX_PORT , PILOTIII_LOCK); //Exit config mode.
658   }
659 
660 
661   return RETURN_SUCCESS;
662 }
663