aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@hp.com>2007-05-08 03:25:55 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-08 14:15:02 -0400
commitd954e8edee5de90f8625c041ce177e04ae2c88fe (patch)
tree671b84441a89b4403017c84c584ec9540ba874f2 /drivers
parent5843205b55d0ec9564289d4b41bab093ae15f51a (diff)
tpm_infineon: add support for devices in mmio space
tAdd adds support for devices living in MMIO space to the Infineon TPM driver. These can be found on some of the newer HP ia64 systems. Signed-off-by: Alex Williamson <alex.williamson@hp.com> Cc: Kylene Jo Hall <kjhall@us.ibm.com> Acked-by: Marcel Selhorst <tpm@selhorst.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/char/tpm/tpm_infineon.c231
1 files changed, 165 insertions, 66 deletions
diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c
index 1353b5a6bae8..967002a5a1e5 100644
--- a/drivers/char/tpm/tpm_infineon.c
+++ b/drivers/char/tpm/tpm_infineon.c
@@ -30,12 +30,60 @@
30#define TPM_MAX_TRIES 5000 30#define TPM_MAX_TRIES 5000
31#define TPM_INFINEON_DEV_VEN_VALUE 0x15D1 31#define TPM_INFINEON_DEV_VEN_VALUE 0x15D1
32 32
33/* These values will be filled after PnP-call */ 33#define TPM_INF_IO_PORT 0x0
34static int TPM_INF_DATA; 34#define TPM_INF_IO_MEM 0x1
35static int TPM_INF_ADDR; 35
36static int TPM_INF_BASE; 36#define TPM_INF_ADDR 0x0
37static int TPM_INF_ADDR_LEN; 37#define TPM_INF_DATA 0x1
38static int TPM_INF_PORT_LEN; 38
39struct tpm_inf_dev {
40 int iotype;
41
42 void __iomem *mem_base; /* MMIO ioremap'd addr */
43 unsigned long map_base; /* phys MMIO base */
44 unsigned long map_size; /* MMIO region size */
45 unsigned int index_off; /* index register offset */
46
47 unsigned int data_regs; /* Data registers */
48 unsigned int data_size;
49
50 unsigned int config_port; /* IO Port config index reg */
51 unsigned int config_size;
52};
53
54static struct tpm_inf_dev tpm_dev;
55
56static inline void tpm_data_out(unsigned char data, unsigned char offset)
57{
58 if (tpm_dev.iotype == TPM_INF_IO_PORT)
59 outb(data, tpm_dev.data_regs + offset);
60 else
61 writeb(data, tpm_dev.mem_base + tpm_dev.data_regs + offset);
62}
63
64static inline unsigned char tpm_data_in(unsigned char offset)
65{
66 if (tpm_dev.iotype == TPM_INF_IO_PORT)
67 return inb(tpm_dev.data_regs + offset);
68 else
69 return readb(tpm_dev.mem_base + tpm_dev.data_regs + offset);
70}
71
72static inline void tpm_config_out(unsigned char data, unsigned char offset)
73{
74 if (tpm_dev.iotype == TPM_INF_IO_PORT)
75 outb(data, tpm_dev.config_port + offset);
76 else
77 writeb(data, tpm_dev.mem_base + tpm_dev.index_off + offset);
78}
79
80static inline unsigned char tpm_config_in(unsigned char offset)
81{
82 if (tpm_dev.iotype == TPM_INF_IO_PORT)
83 return inb(tpm_dev.config_port + offset);
84 else
85 return readb(tpm_dev.mem_base + tpm_dev.index_off + offset);
86}
39 87
40/* TPM header definitions */ 88/* TPM header definitions */
41enum infineon_tpm_header { 89enum infineon_tpm_header {
@@ -105,7 +153,7 @@ static int empty_fifo(struct tpm_chip *chip, int clear_wrfifo)
105 153
106 if (clear_wrfifo) { 154 if (clear_wrfifo) {
107 for (i = 0; i < 4096; i++) { 155 for (i = 0; i < 4096; i++) {
108 status = inb(chip->vendor.base + WRFIFO); 156 status = tpm_data_in(WRFIFO);
109 if (status == 0xff) { 157 if (status == 0xff) {
110 if (check == 5) 158 if (check == 5)
111 break; 159 break;
@@ -125,8 +173,8 @@ static int empty_fifo(struct tpm_chip *chip, int clear_wrfifo)
125 */ 173 */
126 i = 0; 174 i = 0;
127 do { 175 do {
128 status = inb(chip->vendor.base + RDFIFO); 176 status = tpm_data_in(RDFIFO);
129 status = inb(chip->vendor.base + STAT); 177 status = tpm_data_in(STAT);
130 i++; 178 i++;
131 if (i == TPM_MAX_TRIES) 179 if (i == TPM_MAX_TRIES)
132 return -EIO; 180 return -EIO;
@@ -139,7 +187,7 @@ static int wait(struct tpm_chip *chip, int wait_for_bit)
139 int status; 187 int status;
140 int i; 188 int i;
141 for (i = 0; i < TPM_MAX_TRIES; i++) { 189 for (i = 0; i < TPM_MAX_TRIES; i++) {
142 status = inb(chip->vendor.base + STAT); 190 status = tpm_data_in(STAT);
143 /* check the status-register if wait_for_bit is set */ 191 /* check the status-register if wait_for_bit is set */
144 if (status & 1 << wait_for_bit) 192 if (status & 1 << wait_for_bit)
145 break; 193 break;
@@ -158,7 +206,7 @@ static int wait(struct tpm_chip *chip, int wait_for_bit)
158static void wait_and_send(struct tpm_chip *chip, u8 sendbyte) 206static void wait_and_send(struct tpm_chip *chip, u8 sendbyte)
159{ 207{
160 wait(chip, STAT_XFE); 208 wait(chip, STAT_XFE);
161 outb(sendbyte, chip->vendor.base + WRFIFO); 209 tpm_data_out(sendbyte, WRFIFO);
162} 210}
163 211
164 /* Note: WTX means Waiting-Time-Extension. Whenever the TPM needs more 212 /* Note: WTX means Waiting-Time-Extension. Whenever the TPM needs more
@@ -205,7 +253,7 @@ recv_begin:
205 ret = wait(chip, STAT_RDA); 253 ret = wait(chip, STAT_RDA);
206 if (ret) 254 if (ret)
207 return -EIO; 255 return -EIO;
208 buf[i] = inb(chip->vendor.base + RDFIFO); 256 buf[i] = tpm_data_in(RDFIFO);
209 } 257 }
210 258
211 if (buf[0] != TPM_VL_VER) { 259 if (buf[0] != TPM_VL_VER) {
@@ -220,7 +268,7 @@ recv_begin:
220 268
221 for (i = 0; i < size; i++) { 269 for (i = 0; i < size; i++) {
222 wait(chip, STAT_RDA); 270 wait(chip, STAT_RDA);
223 buf[i] = inb(chip->vendor.base + RDFIFO); 271 buf[i] = tpm_data_in(RDFIFO);
224 } 272 }
225 273
226 if ((size == 0x6D00) && (buf[1] == 0x80)) { 274 if ((size == 0x6D00) && (buf[1] == 0x80)) {
@@ -269,7 +317,7 @@ static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count)
269 u8 count_high, count_low, count_4, count_3, count_2, count_1; 317 u8 count_high, count_low, count_4, count_3, count_2, count_1;
270 318
271 /* Disabling Reset, LP and IRQC */ 319 /* Disabling Reset, LP and IRQC */
272 outb(RESET_LP_IRQC_DISABLE, chip->vendor.base + CMD); 320 tpm_data_out(RESET_LP_IRQC_DISABLE, CMD);
273 321
274 ret = empty_fifo(chip, 1); 322 ret = empty_fifo(chip, 1);
275 if (ret) { 323 if (ret) {
@@ -320,7 +368,7 @@ static void tpm_inf_cancel(struct tpm_chip *chip)
320 368
321static u8 tpm_inf_status(struct tpm_chip *chip) 369static u8 tpm_inf_status(struct tpm_chip *chip)
322{ 370{
323 return inb(chip->vendor.base + STAT); 371 return tpm_data_in(STAT);
324} 372}
325 373
326static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); 374static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
@@ -381,51 +429,88 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
381 /* read IO-ports through PnP */ 429 /* read IO-ports through PnP */
382 if (pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && 430 if (pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) &&
383 !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) { 431 !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) {
384 TPM_INF_ADDR = pnp_port_start(dev, 0); 432
385 TPM_INF_ADDR_LEN = pnp_port_len(dev, 0); 433 tpm_dev.iotype = TPM_INF_IO_PORT;
386 TPM_INF_DATA = (TPM_INF_ADDR + 1); 434
387 TPM_INF_BASE = pnp_port_start(dev, 1); 435 tpm_dev.config_port = pnp_port_start(dev, 0);
388 TPM_INF_PORT_LEN = pnp_port_len(dev, 1); 436 tpm_dev.config_size = pnp_port_len(dev, 0);
389 if ((TPM_INF_PORT_LEN < 4) || (TPM_INF_ADDR_LEN < 2)) { 437 tpm_dev.data_regs = pnp_port_start(dev, 1);
438 tpm_dev.data_size = pnp_port_len(dev, 1);
439 if ((tpm_dev.data_size < 4) || (tpm_dev.config_size < 2)) {
390 rc = -EINVAL; 440 rc = -EINVAL;
391 goto err_last; 441 goto err_last;
392 } 442 }
393 dev_info(&dev->dev, "Found %s with ID %s\n", 443 dev_info(&dev->dev, "Found %s with ID %s\n",
394 dev->name, dev_id->id); 444 dev->name, dev_id->id);
395 if (!((TPM_INF_BASE >> 8) & 0xff)) { 445 if (!((tpm_dev.data_regs >> 8) & 0xff)) {
396 rc = -EINVAL; 446 rc = -EINVAL;
397 goto err_last; 447 goto err_last;
398 } 448 }
399 /* publish my base address and request region */ 449 /* publish my base address and request region */
400 if (request_region 450 if (request_region(tpm_dev.data_regs, tpm_dev.data_size,
401 (TPM_INF_BASE, TPM_INF_PORT_LEN, "tpm_infineon0") == NULL) { 451 "tpm_infineon0") == NULL) {
402 rc = -EINVAL; 452 rc = -EINVAL;
403 goto err_last; 453 goto err_last;
404 } 454 }
405 if (request_region 455 if (request_region(tpm_dev.config_port, tpm_dev.config_size,
406 (TPM_INF_ADDR, TPM_INF_ADDR_LEN, "tpm_infineon0") == NULL) { 456 "tpm_infineon0") == NULL) {
457 release_region(tpm_dev.data_regs, tpm_dev.data_size);
407 rc = -EINVAL; 458 rc = -EINVAL;
408 goto err_last; 459 goto err_last;
409 } 460 }
461 } else if (pnp_mem_valid(dev, 0) &&
462 !(pnp_mem_flags(dev, 0) & IORESOURCE_DISABLED)) {
463
464 tpm_dev.iotype = TPM_INF_IO_MEM;
465
466 tpm_dev.map_base = pnp_mem_start(dev, 0);
467 tpm_dev.map_size = pnp_mem_len(dev, 0);
468
469 dev_info(&dev->dev, "Found %s with ID %s\n",
470 dev->name, dev_id->id);
471
472 /* publish my base address and request region */
473 if (request_mem_region(tpm_dev.map_base, tpm_dev.map_size,
474 "tpm_infineon0") == NULL) {
475 rc = -EINVAL;
476 goto err_last;
477 }
478
479 tpm_dev.mem_base = ioremap(tpm_dev.map_base, tpm_dev.map_size);
480 if (tpm_dev.mem_base == NULL) {
481 release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
482 rc = -EINVAL;
483 goto err_last;
484 }
485
486 /*
487 * The only known MMIO based Infineon TPM system provides
488 * a single large mem region with the device config
489 * registers at the default TPM_ADDR. The data registers
490 * seem like they could be placed anywhere within the MMIO
491 * region, but lets just put them at zero offset.
492 */
493 tpm_dev.index_off = TPM_ADDR;
494 tpm_dev.data_regs = 0x0;
410 } else { 495 } else {
411 rc = -EINVAL; 496 rc = -EINVAL;
412 goto err_last; 497 goto err_last;
413 } 498 }
414 499
415 /* query chip for its vendor, its version number a.s.o. */ 500 /* query chip for its vendor, its version number a.s.o. */
416 outb(ENABLE_REGISTER_PAIR, TPM_INF_ADDR); 501 tpm_config_out(ENABLE_REGISTER_PAIR, TPM_INF_ADDR);
417 outb(IDVENL, TPM_INF_ADDR); 502 tpm_config_out(IDVENL, TPM_INF_ADDR);
418 vendorid[1] = inb(TPM_INF_DATA); 503 vendorid[1] = tpm_config_in(TPM_INF_DATA);
419 outb(IDVENH, TPM_INF_ADDR); 504 tpm_config_out(IDVENH, TPM_INF_ADDR);
420 vendorid[0] = inb(TPM_INF_DATA); 505 vendorid[0] = tpm_config_in(TPM_INF_DATA);
421 outb(IDPDL, TPM_INF_ADDR); 506 tpm_config_out(IDPDL, TPM_INF_ADDR);
422 productid[1] = inb(TPM_INF_DATA); 507 productid[1] = tpm_config_in(TPM_INF_DATA);
423 outb(IDPDH, TPM_INF_ADDR); 508 tpm_config_out(IDPDH, TPM_INF_ADDR);
424 productid[0] = inb(TPM_INF_DATA); 509 productid[0] = tpm_config_in(TPM_INF_DATA);
425 outb(CHIP_ID1, TPM_INF_ADDR); 510 tpm_config_out(CHIP_ID1, TPM_INF_ADDR);
426 version[1] = inb(TPM_INF_DATA); 511 version[1] = tpm_config_in(TPM_INF_DATA);
427 outb(CHIP_ID2, TPM_INF_ADDR); 512 tpm_config_out(CHIP_ID2, TPM_INF_ADDR);
428 version[0] = inb(TPM_INF_DATA); 513 version[0] = tpm_config_in(TPM_INF_DATA);
429 514
430 switch ((productid[0] << 8) | productid[1]) { 515 switch ((productid[0] << 8) | productid[1]) {
431 case 6: 516 case 6:
@@ -442,51 +527,54 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
442 if ((vendorid[0] << 8 | vendorid[1]) == (TPM_INFINEON_DEV_VEN_VALUE)) { 527 if ((vendorid[0] << 8 | vendorid[1]) == (TPM_INFINEON_DEV_VEN_VALUE)) {
443 528
444 /* configure TPM with IO-ports */ 529 /* configure TPM with IO-ports */
445 outb(IOLIMH, TPM_INF_ADDR); 530 tpm_config_out(IOLIMH, TPM_INF_ADDR);
446 outb(((TPM_INF_BASE >> 8) & 0xff), TPM_INF_DATA); 531 tpm_config_out((tpm_dev.data_regs >> 8) & 0xff, TPM_INF_DATA);
447 outb(IOLIML, TPM_INF_ADDR); 532 tpm_config_out(IOLIML, TPM_INF_ADDR);
448 outb((TPM_INF_BASE & 0xff), TPM_INF_DATA); 533 tpm_config_out((tpm_dev.data_regs & 0xff), TPM_INF_DATA);
449 534
450 /* control if IO-ports are set correctly */ 535 /* control if IO-ports are set correctly */
451 outb(IOLIMH, TPM_INF_ADDR); 536 tpm_config_out(IOLIMH, TPM_INF_ADDR);
452 ioh = inb(TPM_INF_DATA); 537 ioh = tpm_config_in(TPM_INF_DATA);
453 outb(IOLIML, TPM_INF_ADDR); 538 tpm_config_out(IOLIML, TPM_INF_ADDR);
454 iol = inb(TPM_INF_DATA); 539 iol = tpm_config_in(TPM_INF_DATA);
455 540
456 if ((ioh << 8 | iol) != TPM_INF_BASE) { 541 if ((ioh << 8 | iol) != tpm_dev.data_regs) {
457 dev_err(&dev->dev, 542 dev_err(&dev->dev,
458 "Could not set IO-ports to 0x%x\n", 543 "Could not set IO-data registers to 0x%x\n",
459 TPM_INF_BASE); 544 tpm_dev.data_regs);
460 rc = -EIO; 545 rc = -EIO;
461 goto err_release_region; 546 goto err_release_region;
462 } 547 }
463 548
464 /* activate register */ 549 /* activate register */
465 outb(TPM_DAR, TPM_INF_ADDR); 550 tpm_config_out(TPM_DAR, TPM_INF_ADDR);
466 outb(0x01, TPM_INF_DATA); 551 tpm_config_out(0x01, TPM_INF_DATA);
467 outb(DISABLE_REGISTER_PAIR, TPM_INF_ADDR); 552 tpm_config_out(DISABLE_REGISTER_PAIR, TPM_INF_ADDR);
468 553
469 /* disable RESET, LP and IRQC */ 554 /* disable RESET, LP and IRQC */
470 outb(RESET_LP_IRQC_DISABLE, TPM_INF_BASE + CMD); 555 tpm_data_out(RESET_LP_IRQC_DISABLE, CMD);
471 556
472 /* Finally, we're done, print some infos */ 557 /* Finally, we're done, print some infos */
473 dev_info(&dev->dev, "TPM found: " 558 dev_info(&dev->dev, "TPM found: "
474 "config base 0x%x, " 559 "config base 0x%lx, "
475 "io base 0x%x, " 560 "data base 0x%lx, "
476 "chip version 0x%02x%02x, " 561 "chip version 0x%02x%02x, "
477 "vendor id 0x%x%x (Infineon), " 562 "vendor id 0x%x%x (Infineon), "
478 "product id 0x%02x%02x" 563 "product id 0x%02x%02x"
479 "%s\n", 564 "%s\n",
480 TPM_INF_ADDR, 565 tpm_dev.iotype == TPM_INF_IO_PORT ?
481 TPM_INF_BASE, 566 tpm_dev.config_port :
567 tpm_dev.map_base + tpm_dev.index_off,
568 tpm_dev.iotype == TPM_INF_IO_PORT ?
569 tpm_dev.data_regs :
570 tpm_dev.map_base + tpm_dev.data_regs,
482 version[0], version[1], 571 version[0], version[1],
483 vendorid[0], vendorid[1], 572 vendorid[0], vendorid[1],
484 productid[0], productid[1], chipname); 573 productid[0], productid[1], chipname);
485 574
486 if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf))) { 575 if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf)))
487 goto err_release_region; 576 goto err_release_region;
488 } 577
489 chip->vendor.base = TPM_INF_BASE;
490 return 0; 578 return 0;
491 } else { 579 } else {
492 rc = -ENODEV; 580 rc = -ENODEV;
@@ -494,8 +582,13 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
494 } 582 }
495 583
496err_release_region: 584err_release_region:
497 release_region(TPM_INF_BASE, TPM_INF_PORT_LEN); 585 if (tpm_dev.iotype == TPM_INF_IO_PORT) {
498 release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN); 586 release_region(tpm_dev.data_regs, tpm_dev.data_size);
587 release_region(tpm_dev.config_port, tpm_dev.config_size);
588 } else {
589 iounmap(tpm_dev.mem_base);
590 release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
591 }
499 592
500err_last: 593err_last:
501 return rc; 594 return rc;
@@ -506,8 +599,14 @@ static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev)
506 struct tpm_chip *chip = pnp_get_drvdata(dev); 599 struct tpm_chip *chip = pnp_get_drvdata(dev);
507 600
508 if (chip) { 601 if (chip) {
509 release_region(TPM_INF_BASE, TPM_INF_PORT_LEN); 602 if (tpm_dev.iotype == TPM_INF_IO_PORT) {
510 release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN); 603 release_region(tpm_dev.data_regs, tpm_dev.data_size);
604 release_region(tpm_dev.config_port,
605 tpm_dev.config_size);
606 } else {
607 iounmap(tpm_dev.mem_base);
608 release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
609 }
511 tpm_remove_hardware(chip->dev); 610 tpm_remove_hardware(chip->dev);
512 } 611 }
513} 612}
@@ -539,5 +638,5 @@ module_exit(cleanup_inf);
539 638
540MODULE_AUTHOR("Marcel Selhorst <selhorst@crypto.rub.de>"); 639MODULE_AUTHOR("Marcel Selhorst <selhorst@crypto.rub.de>");
541MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2"); 640MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2");
542MODULE_VERSION("1.8"); 641MODULE_VERSION("1.9");
543MODULE_LICENSE("GPL"); 642MODULE_LICENSE("GPL");