Home | History | Annotate | Download | only in X64
      1 /*++
      2 
      3 Copyright (c) 2005 - 2006, Intel Corporation. All rights reserved.<BR>
      4 This program and the accompanying materials
      5 are licensed and made available under the terms and conditions of the BSD License
      6 which accompanies this distribution.  The full text of the license may be found at
      7 http://opensource.org/licenses/bsd-license.php
      8 
      9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     11 
     12 Module Name:
     13 
     14   PlatformIoLib.c
     15 
     16 Abstract:
     17 
     18 --*/
     19 
     20 #include "Tiano.h"
     21 #include "EfiRuntimeLib.h"
     22 #include EFI_PROTOCOL_DEFINITION (CpuIo)
     23 
     24 #define PCI_CONFIG_INDEX_PORT    0xcf8
     25 #define PCI_CONFIG_DATA_PORT     0xcfc
     26 #define REFRESH_CYCLE_TOGGLE_BIT 0x10
     27 
     28 UINT32
     29 GetPciAddress (
     30   UINT8   Segment,
     31   UINT8   Bus,
     32   UINT8   DevFunc,
     33   UINT8   Register
     34   )
     35 /*++
     36 
     37 Routine Description:
     38   Constructs PCI Address 32 bits
     39 
     40 Arguments:
     41   Segment   - PCI Segment ACPI _SEG
     42   Bus       - PCI Bus
     43   DevFunc   - PCI Device(7:3) and Func(2:0)
     44   Register  - PCI config space register
     45 
     46 Returns:
     47   PciAddress to be written to Config Port
     48 
     49 --*/
     50 {
     51   UINT32  Data;
     52 
     53   Data  = 0;
     54 
     55   Data  = (((UINT32) Segment) << 24);
     56   Data |= (((UINT32) Bus) << 16);
     57   Data |= (((UINT32) DevFunc) << 8);
     58   Data |= (UINT32) Register;
     59 
     60   return Data;
     61 
     62 }
     63 
     64 UINT8
     65 PciRead8 (
     66   UINT8   Segment,
     67   UINT8   Bus,
     68   UINT8   DevFunc,
     69   UINT8   Register
     70   )
     71 /*++
     72 
     73 Routine Description:
     74   Perform an one byte PCI config cycle read
     75 
     76 Arguments:
     77   Segment   - PCI Segment ACPI _SEG
     78   Bus       - PCI Bus
     79   DevFunc   - PCI Device(7:3) and Func(2:0)
     80   Register  - PCI config space register
     81 
     82 Returns:
     83   Data read from PCI config space
     84 
     85 --*/
     86 {
     87   EFI_STATUS  Status;
     88   UINT32      PciAddress;
     89   UINT32      PciAddress1;
     90   UINT8       Data;
     91 
     92   PciAddress = GetPciAddress (Segment, Bus, DevFunc, Register);
     93   //
     94   // Set bit 31 for PCI config access
     95   //
     96   PciAddress1 = PciAddress;
     97   PciAddress  = ((PciAddress & 0xFFFFFFFC) | (0x80000000));
     98 
     99   Status      = EfiIoWrite (EfiCpuIoWidthUint32, PCI_CONFIG_INDEX_PORT, 1, &PciAddress);
    100 
    101   if (EFI_ERROR (Status)) {
    102     return 0;
    103   }
    104 
    105   EfiIoRead (EfiCpuIoWidthUint8, (PCI_CONFIG_DATA_PORT + (PciAddress1 & 0x3)), 1, &Data);
    106 
    107   return Data;
    108 }
    109 
    110 UINT16
    111 PciRead16 (
    112   UINT8   Segment,
    113   UINT8   Bus,
    114   UINT8   DevFunc,
    115   UINT8   Register
    116   )
    117 /*++
    118 
    119 Routine Description:
    120   Perform an two byte PCI config cycle read
    121 
    122 Arguments:
    123   Segment   - PCI Segment ACPI _SEG
    124   Bus       - PCI Bus
    125   DevFunc   - PCI Device(7:3) and Func(2:0)
    126   Register  - PCI config space register
    127 
    128 Returns:
    129   Data read from PCI config space
    130 
    131 --*/
    132 {
    133   EFI_STATUS  Status;
    134   UINT32      PciAddress;
    135   UINT32      PciAddress1;
    136   UINT16      Data;
    137 
    138   PciAddress = GetPciAddress (Segment, Bus, DevFunc, Register);
    139   //
    140   // Set bit 31 for PCI config access
    141   //
    142   PciAddress1 = PciAddress;
    143   PciAddress  = ((PciAddress & 0xFFFFFFFC) | (0x80000000));
    144 
    145   Status      = EfiIoWrite (EfiCpuIoWidthUint32, PCI_CONFIG_INDEX_PORT, 1, &PciAddress);
    146 
    147   if (EFI_ERROR (Status)) {
    148     return 0;
    149   }
    150 
    151   EfiIoRead (EfiCpuIoWidthUint16, (PCI_CONFIG_DATA_PORT + (PciAddress1 & 0x3)), 1, &Data);
    152 
    153   return Data;
    154 }
    155 
    156 UINT32
    157 PciRead32 (
    158   UINT8   Segment,
    159   UINT8   Bus,
    160   UINT8   DevFunc,
    161   UINT8   Register
    162   )
    163 /*++
    164 
    165 Routine Description:
    166   Perform an four byte PCI config cycle read
    167 
    168 Arguments:
    169   Segment   - PCI Segment ACPI _SEG
    170   Bus       - PCI Bus
    171   DevFunc   - PCI Device(7:3) and Func(2:0)
    172   Register  - PCI config space register
    173 
    174 Returns:
    175   Data read from PCI config space
    176 
    177 --*/
    178 {
    179   EFI_STATUS  Status;
    180   UINT32      PciAddress;
    181   UINT32      PciAddress1;
    182   UINT32      Data;
    183 
    184   PciAddress = GetPciAddress (Segment, Bus, DevFunc, Register);
    185   //
    186   // Set bit 31 for PCI config access
    187   //
    188   PciAddress1 = PciAddress;
    189   PciAddress  = ((PciAddress & 0xFFFFFFFC) | (0x80000000));
    190 
    191   Status      = EfiIoWrite (EfiCpuIoWidthUint32, PCI_CONFIG_INDEX_PORT, 1, &PciAddress);
    192 
    193   if (EFI_ERROR (Status)) {
    194     return 0;
    195   }
    196 
    197   EfiIoRead (EfiCpuIoWidthUint32, (PCI_CONFIG_DATA_PORT + (PciAddress1 & 0x3)), 1, &Data);
    198 
    199   return Data;
    200 }
    201 
    202 VOID
    203 PciWrite8 (
    204   UINT8   Segment,
    205   UINT8   Bus,
    206   UINT8   DevFunc,
    207   UINT8   Register,
    208   UINT8   Data
    209   )
    210 /*++
    211 
    212 Routine Description:
    213   Perform an one byte PCI config cycle write
    214 
    215 Arguments:
    216   Segment   - PCI Segment ACPI _SEG
    217   Bus       - PCI Bus
    218   DevFunc   - PCI Device(7:3) and Func(2:0)
    219   Register  - PCI config space register
    220   Data      - Data to write
    221 
    222 Returns:
    223   NONE
    224 
    225 --*/
    226 {
    227   EFI_STATUS  Status;
    228   UINT32      PciAddress;
    229   UINT32      PciAddress1;
    230 
    231   PciAddress = GetPciAddress (Segment, Bus, DevFunc, Register);
    232   //
    233   // Set bit 31 for PCI config access
    234   //
    235   PciAddress1 = PciAddress;
    236   PciAddress  = ((PciAddress & 0xFFFFFFFC) | (0x80000000));
    237 
    238   Status      = EfiIoWrite (EfiCpuIoWidthUint32, PCI_CONFIG_INDEX_PORT, 1, &PciAddress);
    239 
    240   if (EFI_ERROR (Status)) {
    241     return ;
    242   }
    243 
    244   EfiIoWrite (EfiCpuIoWidthUint8, (PCI_CONFIG_DATA_PORT + (PciAddress1 & 0x3)), 1, &Data);
    245 }
    246 
    247 VOID
    248 PciWrite16 (
    249   UINT8   Segment,
    250   UINT8   Bus,
    251   UINT8   DevFunc,
    252   UINT8   Register,
    253   UINT16  Data
    254   )
    255 /*++
    256 
    257 Routine Description:
    258   Perform an two byte PCI config cycle write
    259 
    260 Arguments:
    261   Segment   - PCI Segment ACPI _SEG
    262   Bus       - PCI Bus
    263   DevFunc   - PCI Device(7:3) and Func(2:0)
    264   Register  - PCI config space register
    265   Data      - Data to write
    266 
    267 Returns:
    268   NONE
    269 
    270 --*/
    271 {
    272   EFI_STATUS  Status;
    273   UINT32      PciAddress;
    274   UINT32      PciAddress1;
    275 
    276   PciAddress = GetPciAddress (Segment, Bus, DevFunc, Register);
    277   //
    278   // Set bit 31 for PCI config access
    279   //
    280   PciAddress1 = PciAddress;
    281   PciAddress  = ((PciAddress & 0xFFFFFFFC) | (0x80000000));
    282 
    283   Status      = EfiIoWrite (EfiCpuIoWidthUint32, PCI_CONFIG_INDEX_PORT, 1, &PciAddress);
    284 
    285   if (EFI_ERROR (Status)) {
    286     return ;
    287   }
    288 
    289   EfiIoWrite (EfiCpuIoWidthUint16, (PCI_CONFIG_DATA_PORT + (PciAddress1 & 0x3)), 1, &Data);
    290 }
    291 
    292 VOID
    293 PciWrite32 (
    294   UINT8   Segment,
    295   UINT8   Bus,
    296   UINT8   DevFunc,
    297   UINT8   Register,
    298   UINT32  Data
    299   )
    300 /*++
    301 
    302 Routine Description:
    303   Perform an four byte PCI config cycle write
    304 
    305 Arguments:
    306   Segment   - PCI Segment ACPI _SEG
    307   Bus       - PCI Bus
    308   DevFunc   - PCI Device(7:3) and Func(2:0)
    309   Register  - PCI config space register
    310   Data      - Data to write
    311 
    312 Returns:
    313   NONE
    314 
    315 --*/
    316 {
    317   EFI_STATUS  Status;
    318   UINT32      PciAddress;
    319   UINT32      PciAddress1;
    320 
    321   PciAddress = GetPciAddress (Segment, Bus, DevFunc, Register);
    322   //
    323   // Set bit 31 for PCI config access
    324   //
    325   PciAddress1 = PciAddress;
    326   PciAddress  = ((PciAddress & 0xFFFFFFFC) | (0x80000000));
    327 
    328   Status      = EfiIoWrite (EfiCpuIoWidthUint32, PCI_CONFIG_INDEX_PORT, 1, &PciAddress);
    329 
    330   if (EFI_ERROR (Status)) {
    331     return ;
    332   }
    333 
    334   EfiIoWrite (EfiCpuIoWidthUint32, (PCI_CONFIG_DATA_PORT + (PciAddress1 & 0x3)), 1, &Data);
    335 }
    336 //
    337 // Delay Primative
    338 //
    339 VOID
    340 EfiStall (
    341   IN  UINTN   Microseconds
    342   )
    343 /*++
    344 
    345 Routine Description:
    346  Delay for at least the request number of microseconds
    347 
    348 Arguments:
    349   Microseconds - Number of microseconds to delay.
    350 
    351 Returns:
    352   NONE
    353 
    354 --*/
    355 {
    356   UINT8 Data;
    357   UINT8 InitialState;
    358   UINTN CycleIterations;
    359 
    360   CycleIterations = 0;
    361   Data            = 0;
    362   InitialState    = 0;
    363 
    364   if (EfiAtRuntime ()) {
    365     //
    366     // The time-source is 30 us granular, so calibrate the timing loop
    367     // based on this baseline
    368     // Error is possible 30us.
    369     //
    370     CycleIterations = (Microseconds - 1) / 30 + 1;
    371 
    372     //
    373     // Use the DMA Refresh timer in port 0x61.  Cheap but effective.
    374     // The only issue is that the granularity is 30us, and we want to
    375     // guarantee "at least" one full transition to avoid races.
    376     //
    377     //
    378     //   _____________/----------\__________/--------
    379     //
    380     //                |<--15us-->|<--15us-->|
    381     //
    382     // --------------------------------------------------> Time (us)
    383     //
    384     while (CycleIterations--) {
    385       EfiIoRead (EfiCpuIoWidthUint8, 0x61, 1, &Data);
    386       Data &= REFRESH_CYCLE_TOGGLE_BIT;
    387       InitialState = Data;
    388 
    389       //
    390       // Capture first transition (strictly less than one period)
    391       //
    392       while (InitialState == Data) {
    393         EfiIoRead (EfiCpuIoWidthUint8, 0x61, 1, &Data);
    394         Data &= REFRESH_CYCLE_TOGGLE_BIT;
    395       }
    396 
    397       InitialState = Data;
    398       //
    399       // Capture next transition (guarantee at least one full pulse)
    400       //
    401       while (InitialState == Data) {
    402         EfiIoRead (EfiCpuIoWidthUint8, 0x61, 1, &Data);
    403         Data &= REFRESH_CYCLE_TOGGLE_BIT;
    404       }
    405     }
    406   } else {
    407     gBS->Stall (Microseconds);
    408   }
    409 }
    410