[PATCH] tpm_infineon: Support for new TPM 1.2 and PNPACPI

This patch includes support for the new Infineon Trusted Platform Module
SLB 9635 TT 1.2 and does further include ACPI-support for both chip
versions (SLD 9630 TT 1.1 and SLB9635 TT 1.2). Since the ioports and
configuration registers are not correctly set on some machines, the
configuration is now done via PNPACPI, which reads out the correct values
out of the DSDT-table. Note that you have to have CONFIG_PNP,
CONFIG_ACPI_BUS and CONFIG_PNPACPI enabled to run this driver (assuming
that mainboards including a TPM do have the need for ACPI anyway).

Signed-off-by: Marcel Selhorst <selhorst@crypto.rub.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by Marcel Selhorst and committed by Linus Torvalds f9abb020 30e835e3

+111 -42
+7 -4
drivers/char/tpm/Kconfig
··· 17 obtained at: <http://sourceforge.net/projects/trousers>. To 18 compile this driver as a module, choose M here; the module 19 will be called tpm. If unsure, say N. 20 21 config TCG_NSC 22 tristate "National Semiconductor TPM Interface" ··· 38 as a module, choose M here; the module will be called tpm_atmel. 39 40 config TCG_INFINEON 41 - tristate "Infineon Technologies SLD 9630 TPM Interface" 42 - depends on TCG_TPM 43 ---help--- 44 If you have a TPM security chip from Infineon Technologies 45 - say Yes and it will be accessible from within Linux. To 46 - compile this driver as a module, choose M here; the module 47 will be called tpm_infineon. 48 Further information on this driver and the supported hardware 49 can be found at http://www.prosec.rub.de/tpm
··· 17 obtained at: <http://sourceforge.net/projects/trousers>. To 18 compile this driver as a module, choose M here; the module 19 will be called tpm. If unsure, say N. 20 + Note: For more TPM drivers enable CONFIG_PNP, CONFIG_ACPI_BUS 21 + and CONFIG_PNPACPI. 22 23 config TCG_NSC 24 tristate "National Semiconductor TPM Interface" ··· 36 as a module, choose M here; the module will be called tpm_atmel. 37 38 config TCG_INFINEON 39 + tristate "Infineon Technologies TPM Interface" 40 + depends on TCG_TPM && PNPACPI 41 ---help--- 42 If you have a TPM security chip from Infineon Technologies 43 + (either SLD 9630 TT 1.1 or SLB 9635 TT 1.2) say Yes and it 44 + will be accessible from within Linux. 45 + To compile this driver as a module, choose M here; the module 46 will be called tpm_infineon. 47 Further information on this driver and the supported hardware 48 can be found at http://www.prosec.rub.de/tpm
+104 -38
drivers/char/tpm/tpm_infineon.c
··· 1 /* 2 * Description: 3 * Device Driver for the Infineon Technologies 4 - * SLD 9630 TT Trusted Platform Module 5 * Specifications at www.trustedcomputinggroup.org 6 * 7 * Copyright (C) 2005, Marcel Selhorst <selhorst@crypto.rub.de> ··· 12 * modify it under the terms of the GNU General Public License as 13 * published by the Free Software Foundation, version 2 of the 14 * License. 15 - * 16 */ 17 18 #include "tpm.h" 19 20 /* Infineon specific definitions */ ··· 27 #define TPM_MSLEEP_TIME 3 28 /* gives number of max. msleep()-calls before throwing timeout */ 29 #define TPM_MAX_TRIES 5000 30 - #define TCPA_INFINEON_DEV_VEN_VALUE 0x15D1 31 - #define TPM_DATA (TPM_ADDR + 1) & 0xff 32 33 /* TPM header definitions */ 34 enum infineon_tpm_header { ··· 309 310 static void tpm_inf_cancel(struct tpm_chip *chip) 311 { 312 - /* Nothing yet! 313 - This has something to do with the internal functions 314 - of the TPM. Abort isn't really necessary... 315 */ 316 } 317 ··· 350 .miscdev = {.fops = &inf_ops,}, 351 }; 352 353 static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, 354 const struct pci_device_id *pci_id) 355 { ··· 384 int vendorid[2]; 385 int version[2]; 386 int productid[2]; 387 388 if (pci_enable_device(pci_dev)) 389 return -EIO; 390 391 dev_info(&pci_dev->dev, "LPC-bus found at 0x%x\n", pci_id->device); 392 393 /* query chip for its vendor, its version number a.s.o. */ 394 - outb(ENABLE_REGISTER_PAIR, TPM_ADDR); 395 - outb(IDVENL, TPM_ADDR); 396 - vendorid[1] = inb(TPM_DATA); 397 - outb(IDVENH, TPM_ADDR); 398 - vendorid[0] = inb(TPM_DATA); 399 - outb(IDPDL, TPM_ADDR); 400 - productid[1] = inb(TPM_DATA); 401 - outb(IDPDH, TPM_ADDR); 402 - productid[0] = inb(TPM_DATA); 403 - outb(CHIP_ID1, TPM_ADDR); 404 - version[1] = inb(TPM_DATA); 405 - outb(CHIP_ID2, TPM_ADDR); 406 - version[0] = inb(TPM_DATA); 407 408 - if ((vendorid[0] << 8 | vendorid[1]) == (TCPA_INFINEON_DEV_VEN_VALUE)) { 409 410 - /* read IO-ports from TPM */ 411 - outb(IOLIMH, TPM_ADDR); 412 - ioh = inb(TPM_DATA); 413 - outb(IOLIML, TPM_ADDR); 414 - iol = inb(TPM_DATA); 415 - tpm_inf.base = (ioh << 8) | iol; 416 417 if (tpm_inf.base == 0) { 418 - dev_err(&pci_dev->dev, "No IO-ports set!\n"); 419 pci_disable_device(pci_dev); 420 - return -ENODEV; 421 } 422 423 /* activate register */ 424 - outb(TPM_DAR, TPM_ADDR); 425 - outb(0x01, TPM_DATA); 426 - outb(DISABLE_REGISTER_PAIR, TPM_ADDR); 427 428 /* disable RESET, LP and IRQC */ 429 outb(RESET_LP_IRQC_DISABLE, tpm_inf.base + CMD); 430 431 /* Finally, we're done, print some infos */ 432 dev_info(&pci_dev->dev, "TPM found: " 433 "io base 0x%x, " 434 "chip version %02x%02x, " 435 "vendor id %x%x (Infineon), " 436 "product id %02x%02x" 437 "%s\n", 438 tpm_inf.base, 439 version[0], version[1], 440 vendorid[0], vendorid[1], 441 - productid[0], productid[1], ((productid[0] == 0) 442 - && (productid[1] == 443 - 6)) ? 444 - " (SLD 9630 TT 1.1)" : ""); 445 446 rc = tpm_register_hardware(pci_dev, &tpm_inf); 447 if (rc < 0) { ··· 528 module_exit(cleanup_inf); 529 530 MODULE_AUTHOR("Marcel Selhorst <selhorst@crypto.rub.de>"); 531 - MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT"); 532 - MODULE_VERSION("1.4"); 533 MODULE_LICENSE("GPL");
··· 1 /* 2 * Description: 3 * Device Driver for the Infineon Technologies 4 + * SLD 9630 TT 1.1 and SLB 9635 TT 1.2 Trusted Platform Module 5 * Specifications at www.trustedcomputinggroup.org 6 * 7 * Copyright (C) 2005, Marcel Selhorst <selhorst@crypto.rub.de> ··· 12 * modify it under the terms of the GNU General Public License as 13 * published by the Free Software Foundation, version 2 of the 14 * License. 15 */ 16 17 + #include <acpi/acpi_bus.h> 18 + #include <linux/pnp.h> 19 #include "tpm.h" 20 21 /* Infineon specific definitions */ ··· 26 #define TPM_MSLEEP_TIME 3 27 /* gives number of max. msleep()-calls before throwing timeout */ 28 #define TPM_MAX_TRIES 5000 29 + #define TPM_INFINEON_DEV_VEN_VALUE 0x15D1 30 + 31 + /* These values will be filled after ACPI-call */ 32 + static int TPM_INF_DATA = 0; 33 + static int TPM_INF_ADDR = 0; 34 35 /* TPM header definitions */ 36 enum infineon_tpm_header { ··· 305 306 static void tpm_inf_cancel(struct tpm_chip *chip) 307 { 308 + /* 309 + Since we are using the legacy mode to communicate 310 + with the TPM, we have no cancel functions, but have 311 + a workaround for interrupting the TPM through WTX. 312 */ 313 } 314 ··· 345 .miscdev = {.fops = &inf_ops,}, 346 }; 347 348 + static const struct pnp_device_id tpm_pnp_tbl[] = { 349 + /* Infineon TPMs */ 350 + {"IFX0101", 0}, 351 + {"IFX0102", 0}, 352 + {"", 0} 353 + }; 354 + 355 + static int __devinit tpm_inf_acpi_probe(struct pnp_dev *dev, 356 + const struct pnp_device_id *dev_id) 357 + { 358 + TPM_INF_ADDR = (pnp_port_start(dev, 0) & 0xff); 359 + TPM_INF_DATA = ((TPM_INF_ADDR + 1) & 0xff); 360 + tpm_inf.base = pnp_port_start(dev, 1); 361 + dev_info(&dev->dev, "Found %s with ID %s\n", 362 + dev->name, dev_id->id); 363 + if (!((tpm_inf.base >> 8) & 0xff)) 364 + tpm_inf.base = 0; 365 + return 0; 366 + } 367 + 368 + static struct pnp_driver tpm_inf_pnp = { 369 + .name = "tpm_inf_pnp", 370 + .id_table = tpm_pnp_tbl, 371 + .probe = tpm_inf_acpi_probe, 372 + }; 373 + 374 static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, 375 const struct pci_device_id *pci_id) 376 { ··· 353 int vendorid[2]; 354 int version[2]; 355 int productid[2]; 356 + char chipname[20]; 357 358 if (pci_enable_device(pci_dev)) 359 return -EIO; 360 361 dev_info(&pci_dev->dev, "LPC-bus found at 0x%x\n", pci_id->device); 362 363 + /* read IO-ports from ACPI */ 364 + pnp_register_driver(&tpm_inf_pnp); 365 + pnp_unregister_driver(&tpm_inf_pnp); 366 + 367 + /* Make sure, we have received valid config ports */ 368 + if (!TPM_INF_ADDR) { 369 + pci_disable_device(pci_dev); 370 + return -EIO; 371 + } 372 + 373 /* query chip for its vendor, its version number a.s.o. */ 374 + outb(ENABLE_REGISTER_PAIR, TPM_INF_ADDR); 375 + outb(IDVENL, TPM_INF_ADDR); 376 + vendorid[1] = inb(TPM_INF_DATA); 377 + outb(IDVENH, TPM_INF_ADDR); 378 + vendorid[0] = inb(TPM_INF_DATA); 379 + outb(IDPDL, TPM_INF_ADDR); 380 + productid[1] = inb(TPM_INF_DATA); 381 + outb(IDPDH, TPM_INF_ADDR); 382 + productid[0] = inb(TPM_INF_DATA); 383 + outb(CHIP_ID1, TPM_INF_ADDR); 384 + version[1] = inb(TPM_INF_DATA); 385 + outb(CHIP_ID2, TPM_INF_ADDR); 386 + version[0] = inb(TPM_INF_DATA); 387 388 + switch ((productid[0] << 8) | productid[1]) { 389 + case 6: 390 + sprintf(chipname, " (SLD 9630 TT 1.1)"); 391 + break; 392 + case 11: 393 + sprintf(chipname, " (SLB 9635 TT 1.2)"); 394 + break; 395 + default: 396 + sprintf(chipname, " (unknown chip)"); 397 + break; 398 + } 399 + chipname[19] = 0; 400 401 + if ((vendorid[0] << 8 | vendorid[1]) == (TPM_INFINEON_DEV_VEN_VALUE)) { 402 403 if (tpm_inf.base == 0) { 404 + dev_err(&pci_dev->dev, "No IO-ports found!\n"); 405 pci_disable_device(pci_dev); 406 + return -EIO; 407 + } 408 + /* configure TPM with IO-ports */ 409 + outb(IOLIMH, TPM_INF_ADDR); 410 + outb(((tpm_inf.base >> 8) & 0xff), TPM_INF_DATA); 411 + outb(IOLIML, TPM_INF_ADDR); 412 + outb((tpm_inf.base & 0xff), TPM_INF_DATA); 413 + 414 + /* control if IO-ports are set correctly */ 415 + outb(IOLIMH, TPM_INF_ADDR); 416 + ioh = inb(TPM_INF_DATA); 417 + outb(IOLIML, TPM_INF_ADDR); 418 + iol = inb(TPM_INF_DATA); 419 + 420 + if ((ioh << 8 | iol) != tpm_inf.base) { 421 + dev_err(&pci_dev->dev, 422 + "Could not set IO-ports to %04x\n", 423 + tpm_inf.base); 424 + pci_disable_device(pci_dev); 425 + return -EIO; 426 } 427 428 /* activate register */ 429 + outb(TPM_DAR, TPM_INF_ADDR); 430 + outb(0x01, TPM_INF_DATA); 431 + outb(DISABLE_REGISTER_PAIR, TPM_INF_ADDR); 432 433 /* disable RESET, LP and IRQC */ 434 outb(RESET_LP_IRQC_DISABLE, tpm_inf.base + CMD); 435 436 /* Finally, we're done, print some infos */ 437 dev_info(&pci_dev->dev, "TPM found: " 438 + "config base 0x%x, " 439 "io base 0x%x, " 440 "chip version %02x%02x, " 441 "vendor id %x%x (Infineon), " 442 "product id %02x%02x" 443 "%s\n", 444 + TPM_INF_ADDR, 445 tpm_inf.base, 446 version[0], version[1], 447 vendorid[0], vendorid[1], 448 + productid[0], productid[1], chipname); 449 450 rc = tpm_register_hardware(pci_dev, &tpm_inf); 451 if (rc < 0) { ··· 462 module_exit(cleanup_inf); 463 464 MODULE_AUTHOR("Marcel Selhorst <selhorst@crypto.rub.de>"); 465 + MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2"); 466 + MODULE_VERSION("1.5"); 467 MODULE_LICENSE("GPL");