| /* Copyright (c) 2014 The Regents of the University of California | 
 |  * See LICENSE for details. | 
 |  * | 
 |  * Barret Rhoden <brho@cs.berkeley.edu> */ | 
 |  | 
 | #include <arch/x86.h> | 
 | #include <arch/pci.h> | 
 | #include <trap.h> | 
 | #include <stdio.h> | 
 | #include <string.h> | 
 | #include <assert.h> | 
 | #include <kmalloc.h> | 
 | #include <time.h> | 
 | #include <mm.h> | 
 |  | 
 | /* super-shoddy LPC chip initialization. | 
 |  * | 
 |  * the PCH (old southbridge) is a c602, TBDF x:1f:00 LPC controller | 
 |  * - PMBASE is the mnemonic for "ACPI Base Address" | 
 |  * - TCO is 0x60 off in the PMBASE space | 
 |  * - PMBASE + 0x30 is an SMI control reg | 
 |  * | 
 |  * TODO: | 
 |  * - why don't we find the other functions (1f.2 and 1f.3, in linux)? | 
 |  */ | 
 | static void lpc_init_pci(struct pci_device *pcidev) | 
 | { | 
 | 	uint32_t pmbase = pcidev_read32(pcidev, 0x40); | 
 |  | 
 | 	pmbase &= ~1; /* clear bit 0 */ | 
 | 	uint32_t smi_ctl = inl(pmbase + 0x30); | 
 | 	#if 0 | 
 | 	/* halt the tco timer: this busts things, and won't work with the lock on */ | 
 | 	uint16_t tco1 = inw(pmbase + 0x60 + 0x08); | 
 | 	if (tco1 & (1 << 12)) { | 
 | 		printk("\t\tTCO_LOCK is on!\n"); | 
 | 	} else { | 
 | 		outw(pmbase + 0x60 + 0x08, tco1 & ~(1 << 11)); | 
 | 		tco1 = inw(pmbase + 0x60 + 0x08); | 
 | 	} | 
 | 	#endif | 
 | 	/* bit 6 is another timer, one that messes up c89. */ | 
 | 	outl(pmbase + 0x30, smi_ctl & ~(1 << 6)); | 
 | 	smi_ctl = inl(pmbase + 0x30); | 
 | } | 
 |  | 
 | void intel_lpc_init() | 
 | { | 
 | 	struct pci_device *i; | 
 | 	STAILQ_FOREACH(i, &pci_devices, all_dev) { | 
 | 		if ((i->dev == 0x1f) && (i->func == 0x00)) | 
 | 			lpc_init_pci(i); | 
 | 	} | 
 | } |