Imported Upstream version 3.0
[platform/upstream/gnu-efi.git] / apps / route80h.c
1 #include <efi.h>
2 #include <efilib.h>
3
4 /* this example program changes the Reserved Page Route (RPR) bit on ICH10's General
5  * Control And Status Register (GCS) from LPC to PCI.  In practical terms, it routes
6  * outb to port 80h to the PCI bus. */
7
8 #define GCS_OFFSET_ADDR 0x3410
9 #define GCS_RPR_SHIFT 2
10 #define GCS_RPR_PCI 1
11 #define GCS_RPR_LPC 0
12
13 #define VENDOR_ID_INTEL 0x8086
14 #define DEVICE_ID_LPCIF 0x3a16
15 #define DEVICE_ID_COUGARPOINT_LPCIF 0x1c56
16
17 static EFI_HANDLE ImageHandle;
18
19 typedef struct {
20         uint16_t vendor_id;     /* 00-01 */
21         uint16_t device_id;     /* 02-03 */
22         char pad[0xEB];         /* 04-EF */
23         uint32_t rcba;          /* F0-F3 */
24         uint32_t reserved[3];   /* F4-FF */
25 } lpcif_t;
26
27 static inline void set_bit(volatile uint32_t *flag, int bit, int value)
28 {
29         uint32_t val = *flag;
30         Print(L"current value is 0x%2x\n", val);
31
32         if (value) {
33                 val |= (1 << bit);
34         } else {
35                 val &= ~(1 << bit);
36         }
37         Print(L"setting value to 0x%2x\n", val);
38         *flag = val;
39         val = *flag;
40         Print(L"new value is 0x%2x\n", val);
41 }
42
43 static inline int configspace_matches_ids(void *config, uint32_t vendor_id,
44                                 uint32_t device_id)
45 {
46         uint32_t *cfg = config;
47         if (cfg[0] == vendor_id && cfg[1] == device_id)
48                 return 1;
49         return 0;
50 }
51
52 static int is_device(EFI_PCI_IO *pciio, uint16_t vendor_id, uint16_t device_id)
53 {
54         lpcif_t lpcif;
55         EFI_STATUS rc;
56
57         rc = uefi_call_wrapper(pciio->Pci.Read, 5, pciio, EfiPciIoWidthUint16, 0, 2, &lpcif);
58         if (EFI_ERROR(rc))
59                 return 0;
60
61         if (vendor_id == lpcif.vendor_id && device_id == lpcif.device_id)
62                 return 1;
63         return 0;
64 }
65
66 static EFI_STATUS find_pci_device(uint16_t vendor_id, uint16_t device_id,
67                                 EFI_PCI_IO **pciio)
68 {
69         EFI_STATUS rc;
70         EFI_HANDLE *Handles;
71         UINTN NoHandles;
72         int i;
73
74         if (!pciio)
75                 return EFI_INVALID_PARAMETER;
76
77         rc = LibLocateHandle(ByProtocol, &PciIoProtocol, NULL, &NoHandles,
78                              &Handles);
79         if (EFI_ERROR(rc))
80                 return rc;
81
82         for (i = 0; i < NoHandles; i++) {
83                 void *pciio_tmp = NULL;
84                 rc = uefi_call_wrapper(BS->OpenProtocol, 6, Handles[i],
85                                     &PciIoProtocol, &pciio_tmp, ImageHandle,
86                                     NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
87                 if (EFI_ERROR(rc))
88                         continue;
89                 *pciio = pciio_tmp;
90                 if (!is_device(*pciio, vendor_id, device_id)) {
91                         *pciio = NULL;
92                         continue;
93                 }
94
95                 return EFI_SUCCESS;
96         }
97         return EFI_NOT_FOUND;
98 }
99
100 EFI_STATUS
101 efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab)
102 {
103         InitializeLib(image_handle, systab);
104         EFI_PCI_IO *pciio = NULL;
105         lpcif_t lpcif;
106         EFI_STATUS rc;
107         struct {
108                 uint16_t vendor;
109                 uint16_t device;
110         } devices[] = {
111                 { VENDOR_ID_INTEL, DEVICE_ID_LPCIF },
112                 { VENDOR_ID_INTEL, DEVICE_ID_COUGARPOINT_LPCIF },
113                 { 0, 0 }
114         };
115         int i;
116
117         ImageHandle = image_handle;
118         for (i = 0; devices[i].vendor != 0; i++) {
119                 rc = find_pci_device(devices[i].vendor, devices[i].device, &pciio);
120                 if (EFI_ERROR(rc))
121                         continue;
122         }
123
124         if (rc == EFI_NOT_FOUND) {
125                 Print(L"Device not found.\n");
126                 return rc;
127         } else if (EFI_ERROR(rc)) {
128                 return rc;
129         }
130
131         rc = uefi_call_wrapper(pciio->Pci.Read, 5, pciio, EfiPciIoWidthUint32,
132                 EFI_FIELD_OFFSET(lpcif_t, rcba), 1, &lpcif.rcba);
133         if (EFI_ERROR(rc))
134                 return rc;
135         if (!(lpcif.rcba & 1)) {
136                 Print(L"rcrb is not mapped, cannot route port 80h\n");
137                 return EFI_UNSUPPORTED;
138         }
139         lpcif.rcba &= ~1UL;
140
141         Print(L"rcba: 0x%8x\n", lpcif.rcba, lpcif.rcba);
142         set_bit((uint32_t *)(uint64_t)(lpcif.rcba + GCS_OFFSET_ADDR),
143                      GCS_RPR_SHIFT, GCS_RPR_PCI);
144
145         return EFI_SUCCESS;
146 }