File Index
Files and directories
Sign in
FILE

tpm_infineon.c

File preview with syntax highlighting.

linux-6.19.14/drivers/char/tpm/tpm_infineon.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Description:
  4 * Device Driver for the Infineon Technologies
  5 * SLD 9630 TT 1.1 and SLB 9635 TT 1.2 Trusted Platform Module
  6 * Specifications at www.trustedcomputinggroup.org
  7 *
  8 * Copyright (C) 2005, Marcel Selhorst <tpmdd@selhorst.net>
  9 * Sirrix AG - security technologies <tpmdd@sirrix.com> and
 10 * Applied Data Security Group, Ruhr-University Bochum, Germany
 11 * Project-Homepage: http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/ 
 12 */
 13
 14#include <linux/init.h>
 15#include <linux/pnp.h>
 16#include "tpm.h"
 17
 18/* Infineon specific definitions */
 19/* maximum number of WTX-packages */
 20#define	TPM_MAX_WTX_PACKAGES 	50
 21/* msleep-Time for WTX-packages */
 22#define	TPM_WTX_MSLEEP_TIME 	20
 23/* msleep-Time --> Interval to check status register */
 24#define	TPM_MSLEEP_TIME 	3
 25/* gives number of max. msleep()-calls before throwing timeout */
 26#define	TPM_MAX_TRIES		5000
 27#define	TPM_INFINEON_DEV_VEN_VALUE	0x15D1
 28
 29#define TPM_INF_IO_PORT		0x0
 30#define TPM_INF_IO_MEM		0x1
 31
 32#define TPM_INF_ADDR		0x0
 33#define TPM_INF_DATA		0x1
 34
 35struct tpm_inf_dev {
 36	int iotype;
 37
 38	void __iomem *mem_base;	/* MMIO ioremap'd addr */
 39	unsigned long map_base;	/* phys MMIO base */
 40	unsigned long map_size;	/* MMIO region size */
 41	unsigned int index_off;	/* index register offset */
 42
 43	unsigned int data_regs;	/* Data registers */
 44	unsigned int data_size;
 45
 46	unsigned int config_port;	/* IO Port config index reg */
 47	unsigned int config_size;
 48};
 49
 50static struct tpm_inf_dev tpm_dev;
 51
 52static inline void tpm_data_out(unsigned char data, unsigned char offset)
 53{
 54#ifdef CONFIG_HAS_IOPORT
 55	if (tpm_dev.iotype == TPM_INF_IO_PORT)
 56		outb(data, tpm_dev.data_regs + offset);
 57	else
 58#endif
 59		writeb(data, tpm_dev.mem_base + tpm_dev.data_regs + offset);
 60}
 61
 62static inline unsigned char tpm_data_in(unsigned char offset)
 63{
 64#ifdef CONFIG_HAS_IOPORT
 65	if (tpm_dev.iotype == TPM_INF_IO_PORT)
 66		return inb(tpm_dev.data_regs + offset);
 67#endif
 68	return readb(tpm_dev.mem_base + tpm_dev.data_regs + offset);
 69}
 70
 71static inline void tpm_config_out(unsigned char data, unsigned char offset)
 72{
 73#ifdef CONFIG_HAS_IOPORT
 74	if (tpm_dev.iotype == TPM_INF_IO_PORT)
 75		outb(data, tpm_dev.config_port + offset);
 76	else
 77#endif
 78		writeb(data, tpm_dev.mem_base + tpm_dev.index_off + offset);
 79}
 80
 81static inline unsigned char tpm_config_in(unsigned char offset)
 82{
 83#ifdef CONFIG_HAS_IOPORT
 84	if (tpm_dev.iotype == TPM_INF_IO_PORT)
 85		return inb(tpm_dev.config_port + offset);
 86#endif
 87	return readb(tpm_dev.mem_base + tpm_dev.index_off + offset);
 88}
 89
 90/* TPM header definitions */
 91enum infineon_tpm_header {
 92	TPM_VL_VER = 0x01,
 93	TPM_VL_CHANNEL_CONTROL = 0x07,
 94	TPM_VL_CHANNEL_PERSONALISATION = 0x0A,
 95	TPM_VL_CHANNEL_TPM = 0x0B,
 96	TPM_VL_CONTROL = 0x00,
 97	TPM_INF_NAK = 0x15,
 98	TPM_CTRL_WTX = 0x10,
 99	TPM_CTRL_WTX_ABORT = 0x18,
100	TPM_CTRL_WTX_ABORT_ACK = 0x18,
101	TPM_CTRL_ERROR = 0x20,
102	TPM_CTRL_CHAININGACK = 0x40,
103	TPM_CTRL_CHAINING = 0x80,
104	TPM_CTRL_DATA = 0x04,
105	TPM_CTRL_DATA_CHA = 0x84,
106	TPM_CTRL_DATA_CHA_ACK = 0xC4
107};
108
109enum infineon_tpm_register {
110	WRFIFO = 0x00,
111	RDFIFO = 0x01,
112	STAT = 0x02,
113	CMD = 0x03
114};
115
116enum infineon_tpm_command_bits {
117	CMD_DIS = 0x00,
118	CMD_LP = 0x01,
119	CMD_RES = 0x02,
120	CMD_IRQC = 0x06
121};
122
123enum infineon_tpm_status_bits {
124	STAT_XFE = 0x00,
125	STAT_LPA = 0x01,
126	STAT_FOK = 0x02,
127	STAT_TOK = 0x03,
128	STAT_IRQA = 0x06,
129	STAT_RDA = 0x07
130};
131
132/* some outgoing values */
133enum infineon_tpm_values {
134	CHIP_ID1 = 0x20,
135	CHIP_ID2 = 0x21,
136	TPM_DAR = 0x30,
137	RESET_LP_IRQC_DISABLE = 0x41,
138	ENABLE_REGISTER_PAIR = 0x55,
139	IOLIMH = 0x60,
140	IOLIML = 0x61,
141	DISABLE_REGISTER_PAIR = 0xAA,
142	IDVENL = 0xF1,
143	IDVENH = 0xF2,
144	IDPDL = 0xF3,
145	IDPDH = 0xF4
146};
147
148static int number_of_wtx;
149
150static int empty_fifo(struct tpm_chip *chip, int clear_wrfifo)
151{
152	int status;
153	int check = 0;
154	int i;
155
156	if (clear_wrfifo) {
157		for (i = 0; i < 4096; i++) {
158			status = tpm_data_in(WRFIFO);
159			if (status == 0xff) {
160				if (check == 5)
161					break;
162				else
163					check++;
164			}
165		}
166	}
167	/* Note: The values which are currently in the FIFO of the TPM
168	   are thrown away since there is no usage for them. Usually,
169	   this has nothing to say, since the TPM will give its answer
170	   immediately or will be aborted anyway, so the data here is
171	   usually garbage and useless.
172	   We have to clean this, because the next communication with
173	   the TPM would be rubbish, if there is still some old data
174	   in the Read FIFO.
175	 */
176	i = 0;
177	do {
178		status = tpm_data_in(RDFIFO);
179		status = tpm_data_in(STAT);
180		i++;
181		if (i == TPM_MAX_TRIES)
182			return -EIO;
183	} while ((status & (1 << STAT_RDA)) != 0);
184	return 0;
185}
186
187static int wait(struct tpm_chip *chip, int wait_for_bit)
188{
189	int status;
190	int i;
191	for (i = 0; i < TPM_MAX_TRIES; i++) {
192		status = tpm_data_in(STAT);
193		/* check the status-register if wait_for_bit is set */
194		if (status & 1 << wait_for_bit)
195			break;
196		tpm_msleep(TPM_MSLEEP_TIME);
197	}
198	if (i == TPM_MAX_TRIES) {	/* timeout occurs */
199		if (wait_for_bit == STAT_XFE)
200			dev_err(&chip->dev, "Timeout in wait(STAT_XFE)\n");
201		if (wait_for_bit == STAT_RDA)
202			dev_err(&chip->dev, "Timeout in wait(STAT_RDA)\n");
203		return -EIO;
204	}
205	return 0;
206};
207
208static void wait_and_send(struct tpm_chip *chip, u8 sendbyte)
209{
210	wait(chip, STAT_XFE);
211	tpm_data_out(sendbyte, WRFIFO);
212}
213
214    /* Note: WTX means Waiting-Time-Extension. Whenever the TPM needs more
215       calculation time, it sends a WTX-package, which has to be acknowledged
216       or aborted. This usually occurs if you are hammering the TPM with key
217       creation. Set the maximum number of WTX-packages in the definitions
218       above, if the number is reached, the waiting-time will be denied
219       and the TPM command has to be resend.
220     */
221
222static void tpm_wtx(struct tpm_chip *chip)
223{
224	number_of_wtx++;
225	dev_info(&chip->dev, "Granting WTX (%02d / %02d)\n",
226		 number_of_wtx, TPM_MAX_WTX_PACKAGES);
227	wait_and_send(chip, TPM_VL_VER);
228	wait_and_send(chip, TPM_CTRL_WTX);
229	wait_and_send(chip, 0x00);
230	wait_and_send(chip, 0x00);
231	tpm_msleep(TPM_WTX_MSLEEP_TIME);
232}
233
234static void tpm_wtx_abort(struct tpm_chip *chip)
235{
236	dev_info(&chip->dev, "Aborting WTX\n");
237	wait_and_send(chip, TPM_VL_VER);
238	wait_and_send(chip, TPM_CTRL_WTX_ABORT);
239	wait_and_send(chip, 0x00);
240	wait_and_send(chip, 0x00);
241	number_of_wtx = 0;
242	tpm_msleep(TPM_WTX_MSLEEP_TIME);
243}
244
245static int tpm_inf_recv(struct tpm_chip *chip, u8 * buf, size_t count)
246{
247	int i;
248	int ret;
249	u32 size = 0;
250	number_of_wtx = 0;
251
252recv_begin:
253	/* start receiving header */
254	for (i = 0; i < 4; i++) {
255		ret = wait(chip, STAT_RDA);
256		if (ret)
257			return -EIO;
258		buf[i] = tpm_data_in(RDFIFO);
259	}
260
261	if (buf[0] != TPM_VL_VER) {
262		dev_err(&chip->dev,
263			"Wrong transport protocol implementation!\n");
264		return -EIO;
265	}
266
267	if (buf[1] == TPM_CTRL_DATA) {
268		/* size of the data received */
269		size = ((buf[2] << 8) | buf[3]);
270
271		for (i = 0; i < size; i++) {
272			wait(chip, STAT_RDA);
273			buf[i] = tpm_data_in(RDFIFO);
274		}
275
276		if ((size == 0x6D00) && (buf[1] == 0x80)) {
277			dev_err(&chip->dev, "Error handling on vendor layer!\n");
278			return -EIO;
279		}
280
281		for (i = 0; i < size; i++)
282			buf[i] = buf[i + 6];
283
284		size = size - 6;
285		return size;
286	}
287
288	if (buf[1] == TPM_CTRL_WTX) {
289		dev_info(&chip->dev, "WTX-package received\n");
290		if (number_of_wtx < TPM_MAX_WTX_PACKAGES) {
291			tpm_wtx(chip);
292			goto recv_begin;
293		} else {
294			tpm_wtx_abort(chip);
295			goto recv_begin;
296		}
297	}
298
299	if (buf[1] == TPM_CTRL_WTX_ABORT_ACK) {
300		dev_info(&chip->dev, "WTX-abort acknowledged\n");
301		return size;
302	}
303
304	if (buf[1] == TPM_CTRL_ERROR) {
305		dev_err(&chip->dev, "ERROR-package received:\n");
306		if (buf[4] == TPM_INF_NAK)
307			dev_err(&chip->dev,
308				"-> Negative acknowledgement"
309				" - retransmit command!\n");
310		return -EIO;
311	}
312	return -EIO;
313}
314
315static int tpm_inf_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz,
316			size_t count)
317{
318	int i;
319	int ret;
320	u8 count_high, count_low, count_4, count_3, count_2, count_1;
321
322	/* Disabling Reset, LP and IRQC */
323	tpm_data_out(RESET_LP_IRQC_DISABLE, CMD);
324
325	ret = empty_fifo(chip, 1);
326	if (ret) {
327		dev_err(&chip->dev, "Timeout while clearing FIFO\n");
328		return -EIO;
329	}
330
331	ret = wait(chip, STAT_XFE);
332	if (ret)
333		return -EIO;
334
335	count_4 = (count & 0xff000000) >> 24;
336	count_3 = (count & 0x00ff0000) >> 16;
337	count_2 = (count & 0x0000ff00) >> 8;
338	count_1 = (count & 0x000000ff);
339	count_high = ((count + 6) & 0xffffff00) >> 8;
340	count_low = ((count + 6) & 0x000000ff);
341
342	/* Sending Header */
343	wait_and_send(chip, TPM_VL_VER);
344	wait_and_send(chip, TPM_CTRL_DATA);
345	wait_and_send(chip, count_high);
346	wait_and_send(chip, count_low);
347
348	/* Sending Data Header */
349	wait_and_send(chip, TPM_VL_VER);
350	wait_and_send(chip, TPM_VL_CHANNEL_TPM);
351	wait_and_send(chip, count_4);
352	wait_and_send(chip, count_3);
353	wait_and_send(chip, count_2);
354	wait_and_send(chip, count_1);
355
356	/* Sending Data */
357	for (i = 0; i < count; i++) {
358		wait_and_send(chip, buf[i]);
359	}
360	return 0;
361}
362
363static void tpm_inf_cancel(struct tpm_chip *chip)
364{
365	/*
366	   Since we are using the legacy mode to communicate
367	   with the TPM, we have no cancel functions, but have
368	   a workaround for interrupting the TPM through WTX.
369	 */
370}
371
372static u8 tpm_inf_status(struct tpm_chip *chip)
373{
374	return tpm_data_in(STAT);
375}
376
377static const struct tpm_class_ops tpm_inf = {
378	.recv = tpm_inf_recv,
379	.send = tpm_inf_send,
380	.cancel = tpm_inf_cancel,
381	.status = tpm_inf_status,
382	.req_complete_mask = 0,
383	.req_complete_val = 0,
384};
385
386static const struct pnp_device_id tpm_inf_pnp_tbl[] = {
387	/* Infineon TPMs */
388	{"IFX0101", 0},
389	{"IFX0102", 0},
390	{"", 0}
391};
392
393MODULE_DEVICE_TABLE(pnp, tpm_inf_pnp_tbl);
394
395static int tpm_inf_pnp_probe(struct pnp_dev *dev,
396				       const struct pnp_device_id *dev_id)
397{
398	int rc = 0;
399	u8 iol, ioh;
400	int vendorid[2];
401	int version[2];
402	int productid[2];
403	const char *chipname;
404	struct tpm_chip *chip;
405
406	/* read IO-ports through PnP */
407	if (pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) &&
408	    !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) {
409
410		tpm_dev.iotype = TPM_INF_IO_PORT;
411
412		tpm_dev.config_port = pnp_port_start(dev, 0);
413		tpm_dev.config_size = pnp_port_len(dev, 0);
414		tpm_dev.data_regs = pnp_port_start(dev, 1);
415		tpm_dev.data_size = pnp_port_len(dev, 1);
416		if ((tpm_dev.data_size < 4) || (tpm_dev.config_size < 2)) {
417			rc = -EINVAL;
418			goto err_last;
419		}
420		dev_info(&dev->dev, "Found %s with ID %s\n",
421			 dev->name, dev_id->id);
422		if (!((tpm_dev.data_regs >> 8) & 0xff)) {
423			rc = -EINVAL;
424			goto err_last;
425		}
426		/* publish my base address and request region */
427		if (request_region(tpm_dev.data_regs, tpm_dev.data_size,
428				   "tpm_infineon0") == NULL) {
429			rc = -EINVAL;
430			goto err_last;
431		}
432		if (request_region(tpm_dev.config_port, tpm_dev.config_size,
433				   "tpm_infineon0") == NULL) {
434			release_region(tpm_dev.data_regs, tpm_dev.data_size);
435			rc = -EINVAL;
436			goto err_last;
437		}
438	} else if (pnp_mem_valid(dev, 0) &&
439		   !(pnp_mem_flags(dev, 0) & IORESOURCE_DISABLED)) {
440
441		tpm_dev.iotype = TPM_INF_IO_MEM;
442
443		tpm_dev.map_base = pnp_mem_start(dev, 0);
444		tpm_dev.map_size = pnp_mem_len(dev, 0);
445
446		dev_info(&dev->dev, "Found %s with ID %s\n",
447			 dev->name, dev_id->id);
448
449		/* publish my base address and request region */
450		if (request_mem_region(tpm_dev.map_base, tpm_dev.map_size,
451				       "tpm_infineon0") == NULL) {
452			rc = -EINVAL;
453			goto err_last;
454		}
455
456		tpm_dev.mem_base = ioremap(tpm_dev.map_base, tpm_dev.map_size);
457		if (tpm_dev.mem_base == NULL) {
458			release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
459			rc = -EINVAL;
460			goto err_last;
461		}
462
463		/*
464		 * The only known MMIO based Infineon TPM system provides
465		 * a single large mem region with the device config
466		 * registers at the default TPM_ADDR.  The data registers
467		 * seem like they could be placed anywhere within the MMIO
468		 * region, but lets just put them at zero offset.
469		 */
470		tpm_dev.index_off = TPM_ADDR;
471		tpm_dev.data_regs = 0x0;
472	} else {
473		rc = -EINVAL;
474		goto err_last;
475	}
476
477	/* query chip for its vendor, its version number a.s.o. */
478	tpm_config_out(ENABLE_REGISTER_PAIR, TPM_INF_ADDR);
479	tpm_config_out(IDVENL, TPM_INF_ADDR);
480	vendorid[1] = tpm_config_in(TPM_INF_DATA);
481	tpm_config_out(IDVENH, TPM_INF_ADDR);
482	vendorid[0] = tpm_config_in(TPM_INF_DATA);
483	tpm_config_out(IDPDL, TPM_INF_ADDR);
484	productid[1] = tpm_config_in(TPM_INF_DATA);
485	tpm_config_out(IDPDH, TPM_INF_ADDR);
486	productid[0] = tpm_config_in(TPM_INF_DATA);
487	tpm_config_out(CHIP_ID1, TPM_INF_ADDR);
488	version[1] = tpm_config_in(TPM_INF_DATA);
489	tpm_config_out(CHIP_ID2, TPM_INF_ADDR);
490	version[0] = tpm_config_in(TPM_INF_DATA);
491
492	switch ((productid[0] << 8) | productid[1]) {
493	case 6:
494		chipname = " (SLD 9630 TT 1.1)";
495		break;
496	case 11:
497		chipname = " (SLB 9635 TT 1.2)";
498		break;
499	default:
500		chipname = " (unknown chip)";
501		break;
502	}
503
504	if ((vendorid[0] << 8 | vendorid[1]) == (TPM_INFINEON_DEV_VEN_VALUE)) {
505
506		/* configure TPM with IO-ports */
507		tpm_config_out(IOLIMH, TPM_INF_ADDR);
508		tpm_config_out((tpm_dev.data_regs >> 8) & 0xff, TPM_INF_DATA);
509		tpm_config_out(IOLIML, TPM_INF_ADDR);
510		tpm_config_out((tpm_dev.data_regs & 0xff), TPM_INF_DATA);
511
512		/* control if IO-ports are set correctly */
513		tpm_config_out(IOLIMH, TPM_INF_ADDR);
514		ioh = tpm_config_in(TPM_INF_DATA);
515		tpm_config_out(IOLIML, TPM_INF_ADDR);
516		iol = tpm_config_in(TPM_INF_DATA);
517
518		if ((ioh << 8 | iol) != tpm_dev.data_regs) {
519			dev_err(&dev->dev,
520				"Could not set IO-data registers to 0x%x\n",
521				tpm_dev.data_regs);
522			rc = -EIO;
523			goto err_release_region;
524		}
525
526		/* activate register */
527		tpm_config_out(TPM_DAR, TPM_INF_ADDR);
528		tpm_config_out(0x01, TPM_INF_DATA);
529		tpm_config_out(DISABLE_REGISTER_PAIR, TPM_INF_ADDR);
530
531		/* disable RESET, LP and IRQC */
532		tpm_data_out(RESET_LP_IRQC_DISABLE, CMD);
533
534		/* Finally, we're done, print some infos */
535		dev_info(&dev->dev, "TPM found: "
536			 "config base 0x%lx, "
537			 "data base 0x%lx, "
538			 "chip version 0x%02x%02x, "
539			 "vendor id 0x%x%x (Infineon), "
540			 "product id 0x%02x%02x"
541			 "%s\n",
542			 tpm_dev.iotype == TPM_INF_IO_PORT ?
543			 tpm_dev.config_port :
544			 tpm_dev.map_base + tpm_dev.index_off,
545			 tpm_dev.iotype == TPM_INF_IO_PORT ?
546			 tpm_dev.data_regs :
547			 tpm_dev.map_base + tpm_dev.data_regs,
548			 version[0], version[1],
549			 vendorid[0], vendorid[1],
550			 productid[0], productid[1], chipname);
551
552		chip = tpmm_chip_alloc(&dev->dev, &tpm_inf);
553		if (IS_ERR(chip)) {
554			rc = PTR_ERR(chip);
555			goto err_release_region;
556		}
557
558		rc = tpm_chip_register(chip);
559		if (rc)
560			goto err_release_region;
561
562		return 0;
563	} else {
564		rc = -ENODEV;
565		goto err_release_region;
566	}
567
568err_release_region:
569	if (tpm_dev.iotype == TPM_INF_IO_PORT) {
570		release_region(tpm_dev.data_regs, tpm_dev.data_size);
571		release_region(tpm_dev.config_port, tpm_dev.config_size);
572	} else {
573		iounmap(tpm_dev.mem_base);
574		release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
575	}
576
577err_last:
578	return rc;
579}
580
581static void tpm_inf_pnp_remove(struct pnp_dev *dev)
582{
583	struct tpm_chip *chip = pnp_get_drvdata(dev);
584
585	tpm_chip_unregister(chip);
586
587	if (tpm_dev.iotype == TPM_INF_IO_PORT) {
588		release_region(tpm_dev.data_regs, tpm_dev.data_size);
589		release_region(tpm_dev.config_port,
590			       tpm_dev.config_size);
591	} else {
592		iounmap(tpm_dev.mem_base);
593		release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
594	}
595}
596
597#ifdef CONFIG_PM_SLEEP
598static int tpm_inf_resume(struct device *dev)
599{
600	/* Re-configure TPM after suspending */
601	tpm_config_out(ENABLE_REGISTER_PAIR, TPM_INF_ADDR);
602	tpm_config_out(IOLIMH, TPM_INF_ADDR);
603	tpm_config_out((tpm_dev.data_regs >> 8) & 0xff, TPM_INF_DATA);
604	tpm_config_out(IOLIML, TPM_INF_ADDR);
605	tpm_config_out((tpm_dev.data_regs & 0xff), TPM_INF_DATA);
606	/* activate register */
607	tpm_config_out(TPM_DAR, TPM_INF_ADDR);
608	tpm_config_out(0x01, TPM_INF_DATA);
609	tpm_config_out(DISABLE_REGISTER_PAIR, TPM_INF_ADDR);
610	/* disable RESET, LP and IRQC */
611	tpm_data_out(RESET_LP_IRQC_DISABLE, CMD);
612	return tpm_pm_resume(dev);
613}
614#endif
615static SIMPLE_DEV_PM_OPS(tpm_inf_pm, tpm_pm_suspend, tpm_inf_resume);
616
617static struct pnp_driver tpm_inf_pnp_driver = {
618	.name = "tpm_inf_pnp",
619	.id_table = tpm_inf_pnp_tbl,
620	.probe = tpm_inf_pnp_probe,
621	.remove = tpm_inf_pnp_remove,
622	.driver = {
623		.pm = &tpm_inf_pm,
624	}
625};
626
627module_pnp_driver(tpm_inf_pnp_driver);
628
629MODULE_AUTHOR("Marcel Selhorst <tpmdd@sirrix.com>");
630MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2");
631MODULE_VERSION("1.9.2");
632MODULE_LICENSE("GPL");
~/ Read-only file preview.