diff options
-rw-r--r-- | drivers/char/tpm/tpm_infineon.c | 231 |
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 |
34 | static int TPM_INF_DATA; | 34 | #define TPM_INF_IO_MEM 0x1 |
35 | static int TPM_INF_ADDR; | 35 | |
36 | static int TPM_INF_BASE; | 36 | #define TPM_INF_ADDR 0x0 |
37 | static int TPM_INF_ADDR_LEN; | 37 | #define TPM_INF_DATA 0x1 |
38 | static int TPM_INF_PORT_LEN; | 38 | |
39 | struct 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 | |||
54 | static struct tpm_inf_dev tpm_dev; | ||
55 | |||
56 | static 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 | |||
64 | static 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 | |||
72 | static 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 | |||
80 | static 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 */ |
41 | enum infineon_tpm_header { | 89 | enum 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) | |||
158 | static void wait_and_send(struct tpm_chip *chip, u8 sendbyte) | 206 | static 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 | ||
321 | static u8 tpm_inf_status(struct tpm_chip *chip) | 369 | static 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 | ||
326 | static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); | 374 | static 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 | ||
496 | err_release_region: | 584 | err_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 | ||
500 | err_last: | 593 | err_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 | ||
540 | MODULE_AUTHOR("Marcel Selhorst <selhorst@crypto.rub.de>"); | 639 | MODULE_AUTHOR("Marcel Selhorst <selhorst@crypto.rub.de>"); |
541 | MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2"); | 640 | MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2"); |
542 | MODULE_VERSION("1.8"); | 641 | MODULE_VERSION("1.9"); |
543 | MODULE_LICENSE("GPL"); | 642 | MODULE_LICENSE("GPL"); |