blob: adfff21beb219f9965d50626dfbc582cc016be31 [file] [log] [blame]
Marcel Selhorstebb81fd2005-07-27 11:45:12 -07001/*
2 * Description:
3 * Device Driver for the Infineon Technologies
Marcel Selhorstf9abb022005-08-05 11:59:33 -07004 * SLD 9630 TT 1.1 and SLB 9635 TT 1.2 Trusted Platform Module
Marcel Selhorstebb81fd2005-07-27 11:45:12 -07005 * Specifications at www.trustedcomputinggroup.org
6 *
7 * Copyright (C) 2005, Marcel Selhorst <selhorst@crypto.rub.de>
Marcel Selhorst1b8333b2005-10-30 15:03:27 -08008 * Sirrix AG - security technologies, http://www.sirrix.com and
Marcel Selhorstebb81fd2005-07-27 11:45:12 -07009 * Applied Data Security Group, Ruhr-University Bochum, Germany
10 * Project-Homepage: http://www.prosec.rub.de/tpm
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation, version 2 of the
15 * License.
Marcel Selhorstebb81fd2005-07-27 11:45:12 -070016 */
17
Randy Dunlap397c7182006-04-22 02:39:18 -070018#include <linux/init.h>
Marcel Selhorstf9abb022005-08-05 11:59:33 -070019#include <linux/pnp.h>
Marcel Selhorstebb81fd2005-07-27 11:45:12 -070020#include "tpm.h"
21
22/* Infineon specific definitions */
23/* maximum number of WTX-packages */
24#define TPM_MAX_WTX_PACKAGES 50
25/* msleep-Time for WTX-packages */
26#define TPM_WTX_MSLEEP_TIME 20
27/* msleep-Time --> Interval to check status register */
28#define TPM_MSLEEP_TIME 3
29/* gives number of max. msleep()-calls before throwing timeout */
30#define TPM_MAX_TRIES 5000
Marcel Selhorstf9abb022005-08-05 11:59:33 -070031#define TPM_INFINEON_DEV_VEN_VALUE 0x15D1
32
Marcel Selhorste8a65012005-09-03 15:54:20 -070033/* These values will be filled after PnP-call */
Andrew Mortonb888c872005-10-30 15:03:28 -080034static int TPM_INF_DATA;
35static int TPM_INF_ADDR;
36static int TPM_INF_BASE;
Marcel Selhorst8c9e8772006-02-17 13:52:41 -080037static int TPM_INF_ADDR_LEN;
Andrew Mortonb888c872005-10-30 15:03:28 -080038static int TPM_INF_PORT_LEN;
Marcel Selhorstebb81fd2005-07-27 11:45:12 -070039
40/* TPM header definitions */
41enum infineon_tpm_header {
42 TPM_VL_VER = 0x01,
43 TPM_VL_CHANNEL_CONTROL = 0x07,
44 TPM_VL_CHANNEL_PERSONALISATION = 0x0A,
45 TPM_VL_CHANNEL_TPM = 0x0B,
46 TPM_VL_CONTROL = 0x00,
47 TPM_INF_NAK = 0x15,
48 TPM_CTRL_WTX = 0x10,
49 TPM_CTRL_WTX_ABORT = 0x18,
50 TPM_CTRL_WTX_ABORT_ACK = 0x18,
51 TPM_CTRL_ERROR = 0x20,
52 TPM_CTRL_CHAININGACK = 0x40,
53 TPM_CTRL_CHAINING = 0x80,
54 TPM_CTRL_DATA = 0x04,
55 TPM_CTRL_DATA_CHA = 0x84,
56 TPM_CTRL_DATA_CHA_ACK = 0xC4
57};
58
59enum infineon_tpm_register {
60 WRFIFO = 0x00,
61 RDFIFO = 0x01,
62 STAT = 0x02,
63 CMD = 0x03
64};
65
66enum infineon_tpm_command_bits {
67 CMD_DIS = 0x00,
68 CMD_LP = 0x01,
69 CMD_RES = 0x02,
70 CMD_IRQC = 0x06
71};
72
73enum infineon_tpm_status_bits {
74 STAT_XFE = 0x00,
75 STAT_LPA = 0x01,
76 STAT_FOK = 0x02,
77 STAT_TOK = 0x03,
78 STAT_IRQA = 0x06,
79 STAT_RDA = 0x07
80};
81
82/* some outgoing values */
83enum infineon_tpm_values {
84 CHIP_ID1 = 0x20,
85 CHIP_ID2 = 0x21,
Andrew Morton3dcce8e2005-07-27 11:45:14 -070086 TPM_DAR = 0x30,
Marcel Selhorstebb81fd2005-07-27 11:45:12 -070087 RESET_LP_IRQC_DISABLE = 0x41,
88 ENABLE_REGISTER_PAIR = 0x55,
89 IOLIMH = 0x60,
90 IOLIML = 0x61,
91 DISABLE_REGISTER_PAIR = 0xAA,
92 IDVENL = 0xF1,
93 IDVENH = 0xF2,
94 IDPDL = 0xF3,
95 IDPDH = 0xF4
96};
97
98static int number_of_wtx;
99
100static int empty_fifo(struct tpm_chip *chip, int clear_wrfifo)
101{
102 int status;
103 int check = 0;
104 int i;
105
106 if (clear_wrfifo) {
107 for (i = 0; i < 4096; i++) {
Marcel Selhorste496f5402006-04-22 02:38:42 -0700108 status = inb(chip->vendor.base + WRFIFO);
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700109 if (status == 0xff) {
110 if (check == 5)
111 break;
112 else
113 check++;
114 }
115 }
116 }
117 /* Note: The values which are currently in the FIFO of the TPM
118 are thrown away since there is no usage for them. Usually,
119 this has nothing to say, since the TPM will give its answer
120 immediately or will be aborted anyway, so the data here is
121 usually garbage and useless.
122 We have to clean this, because the next communication with
123 the TPM would be rubbish, if there is still some old data
124 in the Read FIFO.
125 */
126 i = 0;
127 do {
Marcel Selhorste496f5402006-04-22 02:38:42 -0700128 status = inb(chip->vendor.base + RDFIFO);
129 status = inb(chip->vendor.base + STAT);
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700130 i++;
131 if (i == TPM_MAX_TRIES)
132 return -EIO;
133 } while ((status & (1 << STAT_RDA)) != 0);
134 return 0;
135}
136
137static int wait(struct tpm_chip *chip, int wait_for_bit)
138{
139 int status;
140 int i;
141 for (i = 0; i < TPM_MAX_TRIES; i++) {
Marcel Selhorste496f5402006-04-22 02:38:42 -0700142 status = inb(chip->vendor.base + STAT);
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700143 /* check the status-register if wait_for_bit is set */
144 if (status & 1 << wait_for_bit)
145 break;
146 msleep(TPM_MSLEEP_TIME);
147 }
148 if (i == TPM_MAX_TRIES) { /* timeout occurs */
149 if (wait_for_bit == STAT_XFE)
Marcel Selhorst1b8333b2005-10-30 15:03:27 -0800150 dev_err(chip->dev, "Timeout in wait(STAT_XFE)\n");
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700151 if (wait_for_bit == STAT_RDA)
Marcel Selhorst1b8333b2005-10-30 15:03:27 -0800152 dev_err(chip->dev, "Timeout in wait(STAT_RDA)\n");
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700153 return -EIO;
154 }
155 return 0;
156};
157
158static void wait_and_send(struct tpm_chip *chip, u8 sendbyte)
159{
160 wait(chip, STAT_XFE);
Marcel Selhorste496f5402006-04-22 02:38:42 -0700161 outb(sendbyte, chip->vendor.base + WRFIFO);
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700162}
163
164 /* Note: WTX means Waiting-Time-Extension. Whenever the TPM needs more
165 calculation time, it sends a WTX-package, which has to be acknowledged
166 or aborted. This usually occurs if you are hammering the TPM with key
167 creation. Set the maximum number of WTX-packages in the definitions
168 above, if the number is reached, the waiting-time will be denied
169 and the TPM command has to be resend.
170 */
171
172static void tpm_wtx(struct tpm_chip *chip)
173{
174 number_of_wtx++;
Kylene Jo Halle659a3f2005-10-30 15:03:24 -0800175 dev_info(chip->dev, "Granting WTX (%02d / %02d)\n",
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700176 number_of_wtx, TPM_MAX_WTX_PACKAGES);
177 wait_and_send(chip, TPM_VL_VER);
178 wait_and_send(chip, TPM_CTRL_WTX);
179 wait_and_send(chip, 0x00);
180 wait_and_send(chip, 0x00);
181 msleep(TPM_WTX_MSLEEP_TIME);
182}
183
184static void tpm_wtx_abort(struct tpm_chip *chip)
185{
Kylene Jo Halle659a3f2005-10-30 15:03:24 -0800186 dev_info(chip->dev, "Aborting WTX\n");
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700187 wait_and_send(chip, TPM_VL_VER);
188 wait_and_send(chip, TPM_CTRL_WTX_ABORT);
189 wait_and_send(chip, 0x00);
190 wait_and_send(chip, 0x00);
191 number_of_wtx = 0;
192 msleep(TPM_WTX_MSLEEP_TIME);
193}
194
195static int tpm_inf_recv(struct tpm_chip *chip, u8 * buf, size_t count)
196{
197 int i;
198 int ret;
199 u32 size = 0;
Marcel Selhorst8c9e8772006-02-17 13:52:41 -0800200 number_of_wtx = 0;
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700201
202recv_begin:
203 /* start receiving header */
204 for (i = 0; i < 4; i++) {
205 ret = wait(chip, STAT_RDA);
206 if (ret)
207 return -EIO;
Marcel Selhorste496f5402006-04-22 02:38:42 -0700208 buf[i] = inb(chip->vendor.base + RDFIFO);
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700209 }
210
211 if (buf[0] != TPM_VL_VER) {
Kylene Jo Halle659a3f2005-10-30 15:03:24 -0800212 dev_err(chip->dev,
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700213 "Wrong transport protocol implementation!\n");
214 return -EIO;
215 }
216
217 if (buf[1] == TPM_CTRL_DATA) {
218 /* size of the data received */
219 size = ((buf[2] << 8) | buf[3]);
220
221 for (i = 0; i < size; i++) {
222 wait(chip, STAT_RDA);
Marcel Selhorste496f5402006-04-22 02:38:42 -0700223 buf[i] = inb(chip->vendor.base + RDFIFO);
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700224 }
225
226 if ((size == 0x6D00) && (buf[1] == 0x80)) {
Marcel Selhorst1b8333b2005-10-30 15:03:27 -0800227 dev_err(chip->dev, "Error handling on vendor layer!\n");
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700228 return -EIO;
229 }
230
231 for (i = 0; i < size; i++)
232 buf[i] = buf[i + 6];
233
234 size = size - 6;
235 return size;
236 }
237
238 if (buf[1] == TPM_CTRL_WTX) {
Kylene Jo Halle659a3f2005-10-30 15:03:24 -0800239 dev_info(chip->dev, "WTX-package received\n");
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700240 if (number_of_wtx < TPM_MAX_WTX_PACKAGES) {
241 tpm_wtx(chip);
242 goto recv_begin;
243 } else {
244 tpm_wtx_abort(chip);
245 goto recv_begin;
246 }
247 }
248
249 if (buf[1] == TPM_CTRL_WTX_ABORT_ACK) {
Kylene Jo Halle659a3f2005-10-30 15:03:24 -0800250 dev_info(chip->dev, "WTX-abort acknowledged\n");
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700251 return size;
252 }
253
254 if (buf[1] == TPM_CTRL_ERROR) {
Kylene Jo Halle659a3f2005-10-30 15:03:24 -0800255 dev_err(chip->dev, "ERROR-package received:\n");
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700256 if (buf[4] == TPM_INF_NAK)
Kylene Jo Halle659a3f2005-10-30 15:03:24 -0800257 dev_err(chip->dev,
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700258 "-> Negative acknowledgement"
259 " - retransmit command!\n");
260 return -EIO;
261 }
262 return -EIO;
263}
264
265static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count)
266{
267 int i;
268 int ret;
269 u8 count_high, count_low, count_4, count_3, count_2, count_1;
270
271 /* Disabling Reset, LP and IRQC */
Marcel Selhorste496f5402006-04-22 02:38:42 -0700272 outb(RESET_LP_IRQC_DISABLE, chip->vendor.base + CMD);
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700273
274 ret = empty_fifo(chip, 1);
275 if (ret) {
Kylene Jo Halle659a3f2005-10-30 15:03:24 -0800276 dev_err(chip->dev, "Timeout while clearing FIFO\n");
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700277 return -EIO;
278 }
279
280 ret = wait(chip, STAT_XFE);
281 if (ret)
282 return -EIO;
283
284 count_4 = (count & 0xff000000) >> 24;
285 count_3 = (count & 0x00ff0000) >> 16;
286 count_2 = (count & 0x0000ff00) >> 8;
287 count_1 = (count & 0x000000ff);
288 count_high = ((count + 6) & 0xffffff00) >> 8;
289 count_low = ((count + 6) & 0x000000ff);
290
291 /* Sending Header */
292 wait_and_send(chip, TPM_VL_VER);
293 wait_and_send(chip, TPM_CTRL_DATA);
294 wait_and_send(chip, count_high);
295 wait_and_send(chip, count_low);
296
297 /* Sending Data Header */
298 wait_and_send(chip, TPM_VL_VER);
299 wait_and_send(chip, TPM_VL_CHANNEL_TPM);
300 wait_and_send(chip, count_4);
301 wait_and_send(chip, count_3);
302 wait_and_send(chip, count_2);
303 wait_and_send(chip, count_1);
304
305 /* Sending Data */
306 for (i = 0; i < count; i++) {
307 wait_and_send(chip, buf[i]);
308 }
309 return count;
310}
311
312static void tpm_inf_cancel(struct tpm_chip *chip)
313{
Marcel Selhorstf9abb022005-08-05 11:59:33 -0700314 /*
315 Since we are using the legacy mode to communicate
316 with the TPM, we have no cancel functions, but have
317 a workaround for interrupting the TPM through WTX.
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700318 */
319}
320
Kylene Jo Hallb4ed3e32005-10-30 15:03:23 -0800321static u8 tpm_inf_status(struct tpm_chip *chip)
322{
Marcel Selhorste496f5402006-04-22 02:38:42 -0700323 return inb(chip->vendor.base + STAT);
Kylene Jo Hallb4ed3e32005-10-30 15:03:23 -0800324}
325
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700326static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
327static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
328static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
329static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
330
331static struct attribute *inf_attrs[] = {
332 &dev_attr_pubek.attr,
333 &dev_attr_pcrs.attr,
334 &dev_attr_caps.attr,
335 &dev_attr_cancel.attr,
336 NULL,
337};
338
339static struct attribute_group inf_attr_grp = {.attrs = inf_attrs };
340
341static struct file_operations inf_ops = {
342 .owner = THIS_MODULE,
343 .llseek = no_llseek,
344 .open = tpm_open,
345 .read = tpm_read,
346 .write = tpm_write,
347 .release = tpm_release,
348};
349
Marcel Selhorste496f5402006-04-22 02:38:42 -0700350static const struct tpm_vendor_specific tpm_inf = {
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700351 .recv = tpm_inf_recv,
352 .send = tpm_inf_send,
353 .cancel = tpm_inf_cancel,
Kylene Jo Hallb4ed3e32005-10-30 15:03:23 -0800354 .status = tpm_inf_status,
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700355 .req_complete_mask = 0,
356 .req_complete_val = 0,
357 .attr_group = &inf_attr_grp,
358 .miscdev = {.fops = &inf_ops,},
359};
360
Marcel Selhorstf9abb022005-08-05 11:59:33 -0700361static const struct pnp_device_id tpm_pnp_tbl[] = {
362 /* Infineon TPMs */
363 {"IFX0101", 0},
364 {"IFX0102", 0},
365 {"", 0}
366};
Marcel Selhorst1b8333b2005-10-30 15:03:27 -0800367
Marcel Selhorste8a65012005-09-03 15:54:20 -0700368MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl);
Marcel Selhorstf9abb022005-08-05 11:59:33 -0700369
Marcel Selhorste8a65012005-09-03 15:54:20 -0700370static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
Marcel Selhorst1b8333b2005-10-30 15:03:27 -0800371 const struct pnp_device_id *dev_id)
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700372{
373 int rc = 0;
374 u8 iol, ioh;
375 int vendorid[2];
376 int version[2];
377 int productid[2];
Marcel Selhorstf9abb022005-08-05 11:59:33 -0700378 char chipname[20];
Marcel Selhorste496f5402006-04-22 02:38:42 -0700379 struct tpm_chip *chip;
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700380
Marcel Selhorst1b8333b2005-10-30 15:03:27 -0800381 /* read IO-ports through PnP */
382 if (pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) &&
383 !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) {
384 TPM_INF_ADDR = pnp_port_start(dev, 0);
Marcel Selhorst8c9e8772006-02-17 13:52:41 -0800385 TPM_INF_ADDR_LEN = pnp_port_len(dev, 0);
Marcel Selhorst1b8333b2005-10-30 15:03:27 -0800386 TPM_INF_DATA = (TPM_INF_ADDR + 1);
387 TPM_INF_BASE = pnp_port_start(dev, 1);
388 TPM_INF_PORT_LEN = pnp_port_len(dev, 1);
Marcel Selhorst8c9e8772006-02-17 13:52:41 -0800389 if ((TPM_INF_PORT_LEN < 4) || (TPM_INF_ADDR_LEN < 2)) {
390 rc = -EINVAL;
391 goto err_last;
392 }
Marcel Selhorst1b8333b2005-10-30 15:03:27 -0800393 dev_info(&dev->dev, "Found %s with ID %s\n",
394 dev->name, dev_id->id);
Marcel Selhorst8c9e8772006-02-17 13:52:41 -0800395 if (!((TPM_INF_BASE >> 8) & 0xff)) {
396 rc = -EINVAL;
397 goto err_last;
398 }
Marcel Selhorst1b8333b2005-10-30 15:03:27 -0800399 /* publish my base address and request region */
Marcel Selhorst1b8333b2005-10-30 15:03:27 -0800400 if (request_region
Marcel Selhorste496f5402006-04-22 02:38:42 -0700401 (TPM_INF_BASE, TPM_INF_PORT_LEN, "tpm_infineon0") == NULL) {
Marcel Selhorst8c9e8772006-02-17 13:52:41 -0800402 rc = -EINVAL;
403 goto err_last;
404 }
Marcel Selhorste496f5402006-04-22 02:38:42 -0700405 if (request_region
406 (TPM_INF_ADDR, TPM_INF_ADDR_LEN, "tpm_infineon0") == NULL) {
Marcel Selhorst8c9e8772006-02-17 13:52:41 -0800407 rc = -EINVAL;
408 goto err_last;
Marcel Selhorst1b8333b2005-10-30 15:03:27 -0800409 }
Marcel Selhorste8a65012005-09-03 15:54:20 -0700410 } else {
Marcel Selhorst8c9e8772006-02-17 13:52:41 -0800411 rc = -EINVAL;
412 goto err_last;
Marcel Selhorstf9abb022005-08-05 11:59:33 -0700413 }
414
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700415 /* query chip for its vendor, its version number a.s.o. */
Marcel Selhorstf9abb022005-08-05 11:59:33 -0700416 outb(ENABLE_REGISTER_PAIR, TPM_INF_ADDR);
417 outb(IDVENL, TPM_INF_ADDR);
418 vendorid[1] = inb(TPM_INF_DATA);
419 outb(IDVENH, TPM_INF_ADDR);
420 vendorid[0] = inb(TPM_INF_DATA);
421 outb(IDPDL, TPM_INF_ADDR);
422 productid[1] = inb(TPM_INF_DATA);
423 outb(IDPDH, TPM_INF_ADDR);
424 productid[0] = inb(TPM_INF_DATA);
425 outb(CHIP_ID1, TPM_INF_ADDR);
426 version[1] = inb(TPM_INF_DATA);
427 outb(CHIP_ID2, TPM_INF_ADDR);
428 version[0] = inb(TPM_INF_DATA);
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700429
Marcel Selhorstf9abb022005-08-05 11:59:33 -0700430 switch ((productid[0] << 8) | productid[1]) {
431 case 6:
Marcel Selhorste8a65012005-09-03 15:54:20 -0700432 snprintf(chipname, sizeof(chipname), " (SLD 9630 TT 1.1)");
Marcel Selhorstf9abb022005-08-05 11:59:33 -0700433 break;
434 case 11:
Marcel Selhorste8a65012005-09-03 15:54:20 -0700435 snprintf(chipname, sizeof(chipname), " (SLB 9635 TT 1.2)");
Marcel Selhorstf9abb022005-08-05 11:59:33 -0700436 break;
437 default:
Marcel Selhorste8a65012005-09-03 15:54:20 -0700438 snprintf(chipname, sizeof(chipname), " (unknown chip)");
Marcel Selhorstf9abb022005-08-05 11:59:33 -0700439 break;
440 }
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700441
Marcel Selhorstf9abb022005-08-05 11:59:33 -0700442 if ((vendorid[0] << 8 | vendorid[1]) == (TPM_INFINEON_DEV_VEN_VALUE)) {
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700443
Marcel Selhorstf9abb022005-08-05 11:59:33 -0700444 /* configure TPM with IO-ports */
445 outb(IOLIMH, TPM_INF_ADDR);
Marcel Selhorste496f5402006-04-22 02:38:42 -0700446 outb(((TPM_INF_BASE >> 8) & 0xff), TPM_INF_DATA);
Marcel Selhorstf9abb022005-08-05 11:59:33 -0700447 outb(IOLIML, TPM_INF_ADDR);
Marcel Selhorste496f5402006-04-22 02:38:42 -0700448 outb((TPM_INF_BASE & 0xff), TPM_INF_DATA);
Marcel Selhorstf9abb022005-08-05 11:59:33 -0700449
450 /* control if IO-ports are set correctly */
451 outb(IOLIMH, TPM_INF_ADDR);
452 ioh = inb(TPM_INF_DATA);
453 outb(IOLIML, TPM_INF_ADDR);
454 iol = inb(TPM_INF_DATA);
455
Marcel Selhorste496f5402006-04-22 02:38:42 -0700456 if ((ioh << 8 | iol) != TPM_INF_BASE) {
Marcel Selhorst1b8333b2005-10-30 15:03:27 -0800457 dev_err(&dev->dev,
Marcel Selhorste496f5402006-04-22 02:38:42 -0700458 "Could not set IO-ports to 0x%x\n",
459 TPM_INF_BASE);
Marcel Selhorst8c9e8772006-02-17 13:52:41 -0800460 rc = -EIO;
461 goto err_release_region;
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700462 }
463
464 /* activate register */
Marcel Selhorstf9abb022005-08-05 11:59:33 -0700465 outb(TPM_DAR, TPM_INF_ADDR);
466 outb(0x01, TPM_INF_DATA);
467 outb(DISABLE_REGISTER_PAIR, TPM_INF_ADDR);
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700468
469 /* disable RESET, LP and IRQC */
Marcel Selhorste496f5402006-04-22 02:38:42 -0700470 outb(RESET_LP_IRQC_DISABLE, TPM_INF_BASE + CMD);
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700471
472 /* Finally, we're done, print some infos */
Marcel Selhorst1b8333b2005-10-30 15:03:27 -0800473 dev_info(&dev->dev, "TPM found: "
Marcel Selhorstf9abb022005-08-05 11:59:33 -0700474 "config base 0x%x, "
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700475 "io base 0x%x, "
Marcel Selhorste496f5402006-04-22 02:38:42 -0700476 "chip version 0x%02x%02x, "
477 "vendor id 0x%x%x (Infineon), "
478 "product id 0x%02x%02x"
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700479 "%s\n",
Marcel Selhorstf9abb022005-08-05 11:59:33 -0700480 TPM_INF_ADDR,
Marcel Selhorst1b8333b2005-10-30 15:03:27 -0800481 TPM_INF_BASE,
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700482 version[0], version[1],
483 vendorid[0], vendorid[1],
Marcel Selhorstf9abb022005-08-05 11:59:33 -0700484 productid[0], productid[1], chipname);
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700485
Marcel Selhorste496f5402006-04-22 02:38:42 -0700486 if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf))) {
Marcel Selhorst8c9e8772006-02-17 13:52:41 -0800487 goto err_release_region;
Marcel Selhorst1b8333b2005-10-30 15:03:27 -0800488 }
Marcel Selhorste496f5402006-04-22 02:38:42 -0700489 chip->vendor.base = TPM_INF_BASE;
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700490 return 0;
491 } else {
Marcel Selhorst8c9e8772006-02-17 13:52:41 -0800492 rc = -ENODEV;
493 goto err_release_region;
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700494 }
Marcel Selhorst8c9e8772006-02-17 13:52:41 -0800495
496err_release_region:
Marcel Selhorste496f5402006-04-22 02:38:42 -0700497 release_region(TPM_INF_BASE, TPM_INF_PORT_LEN);
Marcel Selhorst8c9e8772006-02-17 13:52:41 -0800498 release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN);
499
500err_last:
501 return rc;
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700502}
503
Marcel Selhorst1b8333b2005-10-30 15:03:27 -0800504static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev)
Kylene Jo Halle659a3f2005-10-30 15:03:24 -0800505{
Marcel Selhorst1b8333b2005-10-30 15:03:27 -0800506 struct tpm_chip *chip = pnp_get_drvdata(dev);
Kylene Jo Halle659a3f2005-10-30 15:03:24 -0800507
Marcel Selhorst1b8333b2005-10-30 15:03:27 -0800508 if (chip) {
Marcel Selhorste496f5402006-04-22 02:38:42 -0700509 release_region(TPM_INF_BASE, TPM_INF_PORT_LEN);
510 release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN);
Kylene Jo Halle659a3f2005-10-30 15:03:24 -0800511 tpm_remove_hardware(chip->dev);
Marcel Selhorst1b8333b2005-10-30 15:03:27 -0800512 }
Kylene Jo Halle659a3f2005-10-30 15:03:24 -0800513}
514
Marcel Selhorst1b8333b2005-10-30 15:03:27 -0800515static struct pnp_driver tpm_inf_pnp = {
516 .name = "tpm_inf_pnp",
517 .driver = {
518 .owner = THIS_MODULE,
519 .suspend = tpm_pm_suspend,
520 .resume = tpm_pm_resume,
521 },
522 .id_table = tpm_pnp_tbl,
523 .probe = tpm_inf_pnp_probe,
Randy Dunlap397c7182006-04-22 02:39:18 -0700524 .remove = __devexit_p(tpm_inf_pnp_remove),
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700525};
526
527static int __init init_inf(void)
528{
Marcel Selhorst1b8333b2005-10-30 15:03:27 -0800529 return pnp_register_driver(&tpm_inf_pnp);
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700530}
531
532static void __exit cleanup_inf(void)
533{
Marcel Selhorst1b8333b2005-10-30 15:03:27 -0800534 pnp_unregister_driver(&tpm_inf_pnp);
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700535}
536
537module_init(init_inf);
538module_exit(cleanup_inf);
539
540MODULE_AUTHOR("Marcel Selhorst <selhorst@crypto.rub.de>");
Marcel Selhorstf9abb022005-08-05 11:59:33 -0700541MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2");
Marcel Selhorste496f5402006-04-22 02:38:42 -0700542MODULE_VERSION("1.8");
Marcel Selhorstebb81fd2005-07-27 11:45:12 -0700543MODULE_LICENSE("GPL");