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