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