tpm: Enable CLKRUN protocol for Braswell systems
To overcome a hardware limitation on Intel Braswell systems, disable CLKRUN protocol during TPM transactions and re-enable once the transaction is completed. Signed-off-by: Azhar Shaikh <azhar.shaikh@intel.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Signed-off-by: James Morris <james.l.morris@oracle.com>
This commit is contained in:
		
							parent
							
								
									f128480f39
								
							
						
					
					
						commit
						5e572cab92
					
				| @ -36,6 +36,10 @@ | ||||
| #include <linux/highmem.h> | ||||
| #include <crypto/hash_info.h> | ||||
| 
 | ||||
| #ifdef CONFIG_X86 | ||||
| #include <asm/intel-family.h> | ||||
| #endif | ||||
| 
 | ||||
| enum tpm_const { | ||||
| 	TPM_MINOR = 224,	/* officially assigned */ | ||||
| 	TPM_BUFSIZE = 4096, | ||||
|  | ||||
| @ -132,13 +132,93 @@ static int check_acpi_tpm2(struct device *dev) | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_X86 | ||||
| #define INTEL_LEGACY_BLK_BASE_ADDR      0xFED08000 | ||||
| #define ILB_REMAP_SIZE			0x100 | ||||
| #define LPC_CNTRL_REG_OFFSET            0x84 | ||||
| #define LPC_CLKRUN_EN                   (1 << 2) | ||||
| 
 | ||||
| void __iomem *ilb_base_addr; | ||||
| 
 | ||||
| static inline bool is_bsw(void) | ||||
| { | ||||
| 	return ((boot_cpu_data.x86_model == INTEL_FAM6_ATOM_AIRMONT) ? 1 : 0); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * tpm_platform_begin_xfer() - clear LPC CLKRUN_EN i.e. clocks will be running | ||||
|  */ | ||||
| static void tpm_platform_begin_xfer(void) | ||||
| { | ||||
| 	u32 clkrun_val; | ||||
| 
 | ||||
| 	if (!is_bsw()) | ||||
| 		return; | ||||
| 
 | ||||
| 	clkrun_val = ioread32(ilb_base_addr + LPC_CNTRL_REG_OFFSET); | ||||
| 
 | ||||
| 	/* Disable LPC CLKRUN# */ | ||||
| 	clkrun_val &= ~LPC_CLKRUN_EN; | ||||
| 	iowrite32(clkrun_val, ilb_base_addr + LPC_CNTRL_REG_OFFSET); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Write any random value on port 0x80 which is on LPC, to make | ||||
| 	 * sure LPC clock is running before sending any TPM command. | ||||
| 	 */ | ||||
| 	outb(0xCC, 0x80); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * tpm_platform_end_xfer() - set LPC CLKRUN_EN i.e. clocks can be turned off | ||||
|  */ | ||||
| static void tpm_platform_end_xfer(void) | ||||
| { | ||||
| 	u32 clkrun_val; | ||||
| 
 | ||||
| 	if (!is_bsw()) | ||||
| 		return; | ||||
| 
 | ||||
| 	clkrun_val = ioread32(ilb_base_addr + LPC_CNTRL_REG_OFFSET); | ||||
| 
 | ||||
| 	/* Enable LPC CLKRUN# */ | ||||
| 	clkrun_val |= LPC_CLKRUN_EN; | ||||
| 	iowrite32(clkrun_val, ilb_base_addr + LPC_CNTRL_REG_OFFSET); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Write any random value on port 0x80 which is on LPC, to make | ||||
| 	 * sure LPC clock is running before sending any TPM command. | ||||
| 	 */ | ||||
| 	outb(0xCC, 0x80); | ||||
| 
 | ||||
| } | ||||
| #else | ||||
| static inline bool is_bsw(void) | ||||
| { | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| static void tpm_platform_begin_xfer(void) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| static void tpm_platform_end_xfer(void) | ||||
| { | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| static int tpm_tcg_read_bytes(struct tpm_tis_data *data, u32 addr, u16 len, | ||||
| 			      u8 *result) | ||||
| { | ||||
| 	struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); | ||||
| 
 | ||||
| 	tpm_platform_begin_xfer(); | ||||
| 
 | ||||
| 	while (len--) | ||||
| 		*result++ = ioread8(phy->iobase + addr); | ||||
| 
 | ||||
| 	tpm_platform_end_xfer(); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -147,8 +227,13 @@ static int tpm_tcg_write_bytes(struct tpm_tis_data *data, u32 addr, u16 len, | ||||
| { | ||||
| 	struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); | ||||
| 
 | ||||
| 	tpm_platform_begin_xfer(); | ||||
| 
 | ||||
| 	while (len--) | ||||
| 		iowrite8(*value++, phy->iobase + addr); | ||||
| 
 | ||||
| 	tpm_platform_end_xfer(); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -156,7 +241,12 @@ static int tpm_tcg_read16(struct tpm_tis_data *data, u32 addr, u16 *result) | ||||
| { | ||||
| 	struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); | ||||
| 
 | ||||
| 	tpm_platform_begin_xfer(); | ||||
| 
 | ||||
| 	*result = ioread16(phy->iobase + addr); | ||||
| 
 | ||||
| 	tpm_platform_end_xfer(); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -164,7 +254,12 @@ static int tpm_tcg_read32(struct tpm_tis_data *data, u32 addr, u32 *result) | ||||
| { | ||||
| 	struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); | ||||
| 
 | ||||
| 	tpm_platform_begin_xfer(); | ||||
| 
 | ||||
| 	*result = ioread32(phy->iobase + addr); | ||||
| 
 | ||||
| 	tpm_platform_end_xfer(); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -172,7 +267,12 @@ static int tpm_tcg_write32(struct tpm_tis_data *data, u32 addr, u32 value) | ||||
| { | ||||
| 	struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); | ||||
| 
 | ||||
| 	tpm_platform_begin_xfer(); | ||||
| 
 | ||||
| 	iowrite32(value, phy->iobase + addr); | ||||
| 
 | ||||
| 	tpm_platform_end_xfer(); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -360,6 +460,11 @@ static int __init init_tis(void) | ||||
| 	if (rc) | ||||
| 		goto err_force; | ||||
| 
 | ||||
| #ifdef CONFIG_X86 | ||||
| 	if (is_bsw()) | ||||
| 		ilb_base_addr = ioremap(INTEL_LEGACY_BLK_BASE_ADDR, | ||||
| 					ILB_REMAP_SIZE); | ||||
| #endif | ||||
| 	rc = platform_driver_register(&tis_drv); | ||||
| 	if (rc) | ||||
| 		goto err_platform; | ||||
| @ -378,6 +483,10 @@ err_pnp: | ||||
| err_platform: | ||||
| 	if (force_pdev) | ||||
| 		platform_device_unregister(force_pdev); | ||||
| #ifdef CONFIG_X86 | ||||
| 	if (is_bsw()) | ||||
| 		iounmap(ilb_base_addr); | ||||
| #endif | ||||
| err_force: | ||||
| 	return rc; | ||||
| } | ||||
| @ -387,6 +496,10 @@ static void __exit cleanup_tis(void) | ||||
| 	pnp_unregister_driver(&tis_pnp_driver); | ||||
| 	platform_driver_unregister(&tis_drv); | ||||
| 
 | ||||
| #ifdef CONFIG_X86 | ||||
| 	if (is_bsw()) | ||||
| 		iounmap(ilb_base_addr); | ||||
| #endif | ||||
| 	if (force_pdev) | ||||
| 		platform_device_unregister(force_pdev); | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user