1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2004 IBM Corporation
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Authors:
6*4882a593Smuzhiyun * Leendert van Doorn <leendert@watson.ibm.com>
7*4882a593Smuzhiyun * Dave Safford <safford@watson.ibm.com>
8*4882a593Smuzhiyun * Reiner Sailer <sailer@watson.ibm.com>
9*4882a593Smuzhiyun * Kylene Hall <kjhall@us.ibm.com>
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * Maintained by: <tpmdd-devel@lists.sourceforge.net>
12*4882a593Smuzhiyun *
13*4882a593Smuzhiyun * Device driver for TCG/TCPA TPM (trusted platform module).
14*4882a593Smuzhiyun * Specifications at www.trustedcomputinggroup.org
15*4882a593Smuzhiyun */
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include <linux/platform_device.h>
18*4882a593Smuzhiyun #include <linux/slab.h>
19*4882a593Smuzhiyun #include "tpm.h"
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun /* National definitions */
22*4882a593Smuzhiyun enum tpm_nsc_addr{
23*4882a593Smuzhiyun TPM_NSC_IRQ = 0x07,
24*4882a593Smuzhiyun TPM_NSC_BASE0_HI = 0x60,
25*4882a593Smuzhiyun TPM_NSC_BASE0_LO = 0x61,
26*4882a593Smuzhiyun TPM_NSC_BASE1_HI = 0x62,
27*4882a593Smuzhiyun TPM_NSC_BASE1_LO = 0x63
28*4882a593Smuzhiyun };
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun enum tpm_nsc_index {
31*4882a593Smuzhiyun NSC_LDN_INDEX = 0x07,
32*4882a593Smuzhiyun NSC_SID_INDEX = 0x20,
33*4882a593Smuzhiyun NSC_LDC_INDEX = 0x30,
34*4882a593Smuzhiyun NSC_DIO_INDEX = 0x60,
35*4882a593Smuzhiyun NSC_CIO_INDEX = 0x62,
36*4882a593Smuzhiyun NSC_IRQ_INDEX = 0x70,
37*4882a593Smuzhiyun NSC_ITS_INDEX = 0x71
38*4882a593Smuzhiyun };
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun enum tpm_nsc_status_loc {
41*4882a593Smuzhiyun NSC_STATUS = 0x01,
42*4882a593Smuzhiyun NSC_COMMAND = 0x01,
43*4882a593Smuzhiyun NSC_DATA = 0x00
44*4882a593Smuzhiyun };
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun /* status bits */
47*4882a593Smuzhiyun enum tpm_nsc_status {
48*4882a593Smuzhiyun NSC_STATUS_OBF = 0x01, /* output buffer full */
49*4882a593Smuzhiyun NSC_STATUS_IBF = 0x02, /* input buffer full */
50*4882a593Smuzhiyun NSC_STATUS_F0 = 0x04, /* F0 */
51*4882a593Smuzhiyun NSC_STATUS_A2 = 0x08, /* A2 */
52*4882a593Smuzhiyun NSC_STATUS_RDY = 0x10, /* ready to receive command */
53*4882a593Smuzhiyun NSC_STATUS_IBR = 0x20 /* ready to receive data */
54*4882a593Smuzhiyun };
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun /* command bits */
57*4882a593Smuzhiyun enum tpm_nsc_cmd_mode {
58*4882a593Smuzhiyun NSC_COMMAND_NORMAL = 0x01, /* normal mode */
59*4882a593Smuzhiyun NSC_COMMAND_EOC = 0x03,
60*4882a593Smuzhiyun NSC_COMMAND_CANCEL = 0x22
61*4882a593Smuzhiyun };
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun struct tpm_nsc_priv {
64*4882a593Smuzhiyun unsigned long base;
65*4882a593Smuzhiyun };
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun /*
68*4882a593Smuzhiyun * Wait for a certain status to appear
69*4882a593Smuzhiyun */
wait_for_stat(struct tpm_chip * chip,u8 mask,u8 val,u8 * data)70*4882a593Smuzhiyun static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun struct tpm_nsc_priv *priv = dev_get_drvdata(&chip->dev);
73*4882a593Smuzhiyun unsigned long stop;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun /* status immediately available check */
76*4882a593Smuzhiyun *data = inb(priv->base + NSC_STATUS);
77*4882a593Smuzhiyun if ((*data & mask) == val)
78*4882a593Smuzhiyun return 0;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun /* wait for status */
81*4882a593Smuzhiyun stop = jiffies + 10 * HZ;
82*4882a593Smuzhiyun do {
83*4882a593Smuzhiyun msleep(TPM_TIMEOUT);
84*4882a593Smuzhiyun *data = inb(priv->base + 1);
85*4882a593Smuzhiyun if ((*data & mask) == val)
86*4882a593Smuzhiyun return 0;
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun while (time_before(jiffies, stop));
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun return -EBUSY;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
nsc_wait_for_ready(struct tpm_chip * chip)93*4882a593Smuzhiyun static int nsc_wait_for_ready(struct tpm_chip *chip)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun struct tpm_nsc_priv *priv = dev_get_drvdata(&chip->dev);
96*4882a593Smuzhiyun int status;
97*4882a593Smuzhiyun unsigned long stop;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun /* status immediately available check */
100*4882a593Smuzhiyun status = inb(priv->base + NSC_STATUS);
101*4882a593Smuzhiyun if (status & NSC_STATUS_OBF)
102*4882a593Smuzhiyun status = inb(priv->base + NSC_DATA);
103*4882a593Smuzhiyun if (status & NSC_STATUS_RDY)
104*4882a593Smuzhiyun return 0;
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun /* wait for status */
107*4882a593Smuzhiyun stop = jiffies + 100;
108*4882a593Smuzhiyun do {
109*4882a593Smuzhiyun msleep(TPM_TIMEOUT);
110*4882a593Smuzhiyun status = inb(priv->base + NSC_STATUS);
111*4882a593Smuzhiyun if (status & NSC_STATUS_OBF)
112*4882a593Smuzhiyun status = inb(priv->base + NSC_DATA);
113*4882a593Smuzhiyun if (status & NSC_STATUS_RDY)
114*4882a593Smuzhiyun return 0;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun while (time_before(jiffies, stop));
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun dev_info(&chip->dev, "wait for ready failed\n");
119*4882a593Smuzhiyun return -EBUSY;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun
tpm_nsc_recv(struct tpm_chip * chip,u8 * buf,size_t count)123*4882a593Smuzhiyun static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun struct tpm_nsc_priv *priv = dev_get_drvdata(&chip->dev);
126*4882a593Smuzhiyun u8 *buffer = buf;
127*4882a593Smuzhiyun u8 data, *p;
128*4882a593Smuzhiyun u32 size;
129*4882a593Smuzhiyun __be32 *native_size;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun if (count < 6)
132*4882a593Smuzhiyun return -EIO;
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun if (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0) {
135*4882a593Smuzhiyun dev_err(&chip->dev, "F0 timeout\n");
136*4882a593Smuzhiyun return -EIO;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun data = inb(priv->base + NSC_DATA);
140*4882a593Smuzhiyun if (data != NSC_COMMAND_NORMAL) {
141*4882a593Smuzhiyun dev_err(&chip->dev, "not in normal mode (0x%x)\n",
142*4882a593Smuzhiyun data);
143*4882a593Smuzhiyun return -EIO;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun /* read the whole packet */
147*4882a593Smuzhiyun for (p = buffer; p < &buffer[count]; p++) {
148*4882a593Smuzhiyun if (wait_for_stat
149*4882a593Smuzhiyun (chip, NSC_STATUS_OBF, NSC_STATUS_OBF, &data) < 0) {
150*4882a593Smuzhiyun dev_err(&chip->dev,
151*4882a593Smuzhiyun "OBF timeout (while reading data)\n");
152*4882a593Smuzhiyun return -EIO;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun if (data & NSC_STATUS_F0)
155*4882a593Smuzhiyun break;
156*4882a593Smuzhiyun *p = inb(priv->base + NSC_DATA);
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun if ((data & NSC_STATUS_F0) == 0 &&
160*4882a593Smuzhiyun (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0)) {
161*4882a593Smuzhiyun dev_err(&chip->dev, "F0 not set\n");
162*4882a593Smuzhiyun return -EIO;
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun data = inb(priv->base + NSC_DATA);
166*4882a593Smuzhiyun if (data != NSC_COMMAND_EOC) {
167*4882a593Smuzhiyun dev_err(&chip->dev,
168*4882a593Smuzhiyun "expected end of command(0x%x)\n", data);
169*4882a593Smuzhiyun return -EIO;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun native_size = (__force __be32 *) (buf + 2);
173*4882a593Smuzhiyun size = be32_to_cpu(*native_size);
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun if (count < size)
176*4882a593Smuzhiyun return -EIO;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun return size;
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
tpm_nsc_send(struct tpm_chip * chip,u8 * buf,size_t count)181*4882a593Smuzhiyun static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun struct tpm_nsc_priv *priv = dev_get_drvdata(&chip->dev);
184*4882a593Smuzhiyun u8 data;
185*4882a593Smuzhiyun int i;
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun /*
188*4882a593Smuzhiyun * If we hit the chip with back to back commands it locks up
189*4882a593Smuzhiyun * and never set IBF. Hitting it with this "hammer" seems to
190*4882a593Smuzhiyun * fix it. Not sure why this is needed, we followed the flow
191*4882a593Smuzhiyun * chart in the manual to the letter.
192*4882a593Smuzhiyun */
193*4882a593Smuzhiyun outb(NSC_COMMAND_CANCEL, priv->base + NSC_COMMAND);
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun if (nsc_wait_for_ready(chip) != 0)
196*4882a593Smuzhiyun return -EIO;
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
199*4882a593Smuzhiyun dev_err(&chip->dev, "IBF timeout\n");
200*4882a593Smuzhiyun return -EIO;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun outb(NSC_COMMAND_NORMAL, priv->base + NSC_COMMAND);
204*4882a593Smuzhiyun if (wait_for_stat(chip, NSC_STATUS_IBR, NSC_STATUS_IBR, &data) < 0) {
205*4882a593Smuzhiyun dev_err(&chip->dev, "IBR timeout\n");
206*4882a593Smuzhiyun return -EIO;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun for (i = 0; i < count; i++) {
210*4882a593Smuzhiyun if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
211*4882a593Smuzhiyun dev_err(&chip->dev,
212*4882a593Smuzhiyun "IBF timeout (while writing data)\n");
213*4882a593Smuzhiyun return -EIO;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun outb(buf[i], priv->base + NSC_DATA);
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
219*4882a593Smuzhiyun dev_err(&chip->dev, "IBF timeout\n");
220*4882a593Smuzhiyun return -EIO;
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun outb(NSC_COMMAND_EOC, priv->base + NSC_COMMAND);
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun return 0;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
tpm_nsc_cancel(struct tpm_chip * chip)227*4882a593Smuzhiyun static void tpm_nsc_cancel(struct tpm_chip *chip)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun struct tpm_nsc_priv *priv = dev_get_drvdata(&chip->dev);
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun outb(NSC_COMMAND_CANCEL, priv->base + NSC_COMMAND);
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
tpm_nsc_status(struct tpm_chip * chip)234*4882a593Smuzhiyun static u8 tpm_nsc_status(struct tpm_chip *chip)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun struct tpm_nsc_priv *priv = dev_get_drvdata(&chip->dev);
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun return inb(priv->base + NSC_STATUS);
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun
tpm_nsc_req_canceled(struct tpm_chip * chip,u8 status)241*4882a593Smuzhiyun static bool tpm_nsc_req_canceled(struct tpm_chip *chip, u8 status)
242*4882a593Smuzhiyun {
243*4882a593Smuzhiyun return (status == NSC_STATUS_RDY);
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun static const struct tpm_class_ops tpm_nsc = {
247*4882a593Smuzhiyun .recv = tpm_nsc_recv,
248*4882a593Smuzhiyun .send = tpm_nsc_send,
249*4882a593Smuzhiyun .cancel = tpm_nsc_cancel,
250*4882a593Smuzhiyun .status = tpm_nsc_status,
251*4882a593Smuzhiyun .req_complete_mask = NSC_STATUS_OBF,
252*4882a593Smuzhiyun .req_complete_val = NSC_STATUS_OBF,
253*4882a593Smuzhiyun .req_canceled = tpm_nsc_req_canceled,
254*4882a593Smuzhiyun };
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun static struct platform_device *pdev = NULL;
257*4882a593Smuzhiyun
tpm_nsc_remove(struct device * dev)258*4882a593Smuzhiyun static void tpm_nsc_remove(struct device *dev)
259*4882a593Smuzhiyun {
260*4882a593Smuzhiyun struct tpm_chip *chip = dev_get_drvdata(dev);
261*4882a593Smuzhiyun struct tpm_nsc_priv *priv = dev_get_drvdata(&chip->dev);
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun tpm_chip_unregister(chip);
264*4882a593Smuzhiyun release_region(priv->base, 2);
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun static SIMPLE_DEV_PM_OPS(tpm_nsc_pm, tpm_pm_suspend, tpm_pm_resume);
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun static struct platform_driver nsc_drv = {
270*4882a593Smuzhiyun .driver = {
271*4882a593Smuzhiyun .name = "tpm_nsc",
272*4882a593Smuzhiyun .pm = &tpm_nsc_pm,
273*4882a593Smuzhiyun },
274*4882a593Smuzhiyun };
275*4882a593Smuzhiyun
tpm_read_index(int base,int index)276*4882a593Smuzhiyun static inline int tpm_read_index(int base, int index)
277*4882a593Smuzhiyun {
278*4882a593Smuzhiyun outb(index, base);
279*4882a593Smuzhiyun return inb(base+1) & 0xFF;
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun
tpm_write_index(int base,int index,int value)282*4882a593Smuzhiyun static inline void tpm_write_index(int base, int index, int value)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun outb(index, base);
285*4882a593Smuzhiyun outb(value & 0xFF, base+1);
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun
init_nsc(void)288*4882a593Smuzhiyun static int __init init_nsc(void)
289*4882a593Smuzhiyun {
290*4882a593Smuzhiyun int rc = 0;
291*4882a593Smuzhiyun int lo, hi, err;
292*4882a593Smuzhiyun int nscAddrBase = TPM_ADDR;
293*4882a593Smuzhiyun struct tpm_chip *chip;
294*4882a593Smuzhiyun unsigned long base;
295*4882a593Smuzhiyun struct tpm_nsc_priv *priv;
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun /* verify that it is a National part (SID) */
298*4882a593Smuzhiyun if (tpm_read_index(TPM_ADDR, NSC_SID_INDEX) != 0xEF) {
299*4882a593Smuzhiyun nscAddrBase = (tpm_read_index(TPM_SUPERIO_ADDR, 0x2C)<<8)|
300*4882a593Smuzhiyun (tpm_read_index(TPM_SUPERIO_ADDR, 0x2B)&0xFE);
301*4882a593Smuzhiyun if (tpm_read_index(nscAddrBase, NSC_SID_INDEX) != 0xF6)
302*4882a593Smuzhiyun return -ENODEV;
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun err = platform_driver_register(&nsc_drv);
306*4882a593Smuzhiyun if (err)
307*4882a593Smuzhiyun return err;
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun hi = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_HI);
310*4882a593Smuzhiyun lo = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_LO);
311*4882a593Smuzhiyun base = (hi<<8) | lo;
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun /* enable the DPM module */
314*4882a593Smuzhiyun tpm_write_index(nscAddrBase, NSC_LDC_INDEX, 0x01);
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun pdev = platform_device_alloc("tpm_nscl0", -1);
317*4882a593Smuzhiyun if (!pdev) {
318*4882a593Smuzhiyun rc = -ENOMEM;
319*4882a593Smuzhiyun goto err_unreg_drv;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun pdev->num_resources = 0;
323*4882a593Smuzhiyun pdev->dev.driver = &nsc_drv.driver;
324*4882a593Smuzhiyun pdev->dev.release = tpm_nsc_remove;
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun if ((rc = platform_device_add(pdev)) < 0)
327*4882a593Smuzhiyun goto err_put_dev;
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
330*4882a593Smuzhiyun if (!priv) {
331*4882a593Smuzhiyun rc = -ENOMEM;
332*4882a593Smuzhiyun goto err_del_dev;
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun priv->base = base;
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun if (request_region(base, 2, "tpm_nsc0") == NULL ) {
338*4882a593Smuzhiyun rc = -EBUSY;
339*4882a593Smuzhiyun goto err_del_dev;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun chip = tpmm_chip_alloc(&pdev->dev, &tpm_nsc);
343*4882a593Smuzhiyun if (IS_ERR(chip)) {
344*4882a593Smuzhiyun rc = -ENODEV;
345*4882a593Smuzhiyun goto err_rel_reg;
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun dev_set_drvdata(&chip->dev, priv);
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun rc = tpm_chip_register(chip);
351*4882a593Smuzhiyun if (rc)
352*4882a593Smuzhiyun goto err_rel_reg;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun dev_dbg(&pdev->dev, "NSC TPM detected\n");
355*4882a593Smuzhiyun dev_dbg(&pdev->dev,
356*4882a593Smuzhiyun "NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n",
357*4882a593Smuzhiyun tpm_read_index(nscAddrBase,0x07), tpm_read_index(nscAddrBase,0x20),
358*4882a593Smuzhiyun tpm_read_index(nscAddrBase,0x27));
359*4882a593Smuzhiyun dev_dbg(&pdev->dev,
360*4882a593Smuzhiyun "NSC SIOCF1 0x%x SIOCF5 0x%x SIOCF6 0x%x SIOCF8 0x%x\n",
361*4882a593Smuzhiyun tpm_read_index(nscAddrBase,0x21), tpm_read_index(nscAddrBase,0x25),
362*4882a593Smuzhiyun tpm_read_index(nscAddrBase,0x26), tpm_read_index(nscAddrBase,0x28));
363*4882a593Smuzhiyun dev_dbg(&pdev->dev, "NSC IO Base0 0x%x\n",
364*4882a593Smuzhiyun (tpm_read_index(nscAddrBase,0x60) << 8) | tpm_read_index(nscAddrBase,0x61));
365*4882a593Smuzhiyun dev_dbg(&pdev->dev, "NSC IO Base1 0x%x\n",
366*4882a593Smuzhiyun (tpm_read_index(nscAddrBase,0x62) << 8) | tpm_read_index(nscAddrBase,0x63));
367*4882a593Smuzhiyun dev_dbg(&pdev->dev, "NSC Interrupt number and wakeup 0x%x\n",
368*4882a593Smuzhiyun tpm_read_index(nscAddrBase,0x70));
369*4882a593Smuzhiyun dev_dbg(&pdev->dev, "NSC IRQ type select 0x%x\n",
370*4882a593Smuzhiyun tpm_read_index(nscAddrBase,0x71));
371*4882a593Smuzhiyun dev_dbg(&pdev->dev,
372*4882a593Smuzhiyun "NSC DMA channel select0 0x%x, select1 0x%x\n",
373*4882a593Smuzhiyun tpm_read_index(nscAddrBase,0x74), tpm_read_index(nscAddrBase,0x75));
374*4882a593Smuzhiyun dev_dbg(&pdev->dev,
375*4882a593Smuzhiyun "NSC Config "
376*4882a593Smuzhiyun "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
377*4882a593Smuzhiyun tpm_read_index(nscAddrBase,0xF0), tpm_read_index(nscAddrBase,0xF1),
378*4882a593Smuzhiyun tpm_read_index(nscAddrBase,0xF2), tpm_read_index(nscAddrBase,0xF3),
379*4882a593Smuzhiyun tpm_read_index(nscAddrBase,0xF4), tpm_read_index(nscAddrBase,0xF5),
380*4882a593Smuzhiyun tpm_read_index(nscAddrBase,0xF6), tpm_read_index(nscAddrBase,0xF7),
381*4882a593Smuzhiyun tpm_read_index(nscAddrBase,0xF8), tpm_read_index(nscAddrBase,0xF9));
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun dev_info(&pdev->dev,
384*4882a593Smuzhiyun "NSC TPM revision %d\n",
385*4882a593Smuzhiyun tpm_read_index(nscAddrBase, 0x27) & 0x1F);
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun return 0;
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun err_rel_reg:
390*4882a593Smuzhiyun release_region(base, 2);
391*4882a593Smuzhiyun err_del_dev:
392*4882a593Smuzhiyun platform_device_del(pdev);
393*4882a593Smuzhiyun err_put_dev:
394*4882a593Smuzhiyun platform_device_put(pdev);
395*4882a593Smuzhiyun err_unreg_drv:
396*4882a593Smuzhiyun platform_driver_unregister(&nsc_drv);
397*4882a593Smuzhiyun return rc;
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun
cleanup_nsc(void)400*4882a593Smuzhiyun static void __exit cleanup_nsc(void)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun if (pdev) {
403*4882a593Smuzhiyun tpm_nsc_remove(&pdev->dev);
404*4882a593Smuzhiyun platform_device_unregister(pdev);
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun platform_driver_unregister(&nsc_drv);
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun module_init(init_nsc);
411*4882a593Smuzhiyun module_exit(cleanup_nsc);
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
414*4882a593Smuzhiyun MODULE_DESCRIPTION("TPM Driver");
415*4882a593Smuzhiyun MODULE_VERSION("2.0");
416*4882a593Smuzhiyun MODULE_LICENSE("GPL");
417