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