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