diff options
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/tpm/tpm.h | 6 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_atmel.c | 108 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_atmel.h | 129 |
3 files changed, 171 insertions, 72 deletions
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 9293bcc4dc62..ad51c6538034 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h | |||
@@ -50,7 +50,11 @@ struct tpm_vendor_specific { | |||
50 | u8 req_complete_mask; | 50 | u8 req_complete_mask; |
51 | u8 req_complete_val; | 51 | u8 req_complete_val; |
52 | u8 req_canceled; | 52 | u8 req_canceled; |
53 | u16 base; /* TPM base address */ | 53 | void __iomem *iobase; /* ioremapped address */ |
54 | unsigned long base; /* TPM base address */ | ||
55 | |||
56 | int region_size; | ||
57 | int have_region; | ||
54 | 58 | ||
55 | int (*recv) (struct tpm_chip *, u8 *, size_t); | 59 | int (*recv) (struct tpm_chip *, u8 *, size_t); |
56 | int (*send) (struct tpm_chip *, u8 *, size_t); | 60 | int (*send) (struct tpm_chip *, u8 *, size_t); |
diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index 32e01450c425..deb4b5c80914 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c | |||
@@ -19,14 +19,8 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <linux/platform_device.h> | ||
23 | #include "tpm.h" | 22 | #include "tpm.h" |
24 | 23 | #include "tpm_atmel.h" | |
25 | /* Atmel definitions */ | ||
26 | enum tpm_atmel_addr { | ||
27 | TPM_ATMEL_BASE_ADDR_LO = 0x08, | ||
28 | TPM_ATMEL_BASE_ADDR_HI = 0x09 | ||
29 | }; | ||
30 | 24 | ||
31 | /* write status bits */ | 25 | /* write status bits */ |
32 | enum tpm_atmel_write_status { | 26 | enum tpm_atmel_write_status { |
@@ -53,13 +47,13 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) | |||
53 | return -EIO; | 47 | return -EIO; |
54 | 48 | ||
55 | for (i = 0; i < 6; i++) { | 49 | for (i = 0; i < 6; i++) { |
56 | status = inb(chip->vendor->base + 1); | 50 | status = atmel_getb(chip, 1); |
57 | if ((status & ATML_STATUS_DATA_AVAIL) == 0) { | 51 | if ((status & ATML_STATUS_DATA_AVAIL) == 0) { |
58 | dev_err(chip->dev, | 52 | dev_err(chip->dev, |
59 | "error reading header\n"); | 53 | "error reading header\n"); |
60 | return -EIO; | 54 | return -EIO; |
61 | } | 55 | } |
62 | *buf++ = inb(chip->vendor->base); | 56 | *buf++ = atmel_getb(chip, 0); |
63 | } | 57 | } |
64 | 58 | ||
65 | /* size of the data received */ | 59 | /* size of the data received */ |
@@ -70,7 +64,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) | |||
70 | dev_err(chip->dev, | 64 | dev_err(chip->dev, |
71 | "Recv size(%d) less than available space\n", size); | 65 | "Recv size(%d) less than available space\n", size); |
72 | for (; i < size; i++) { /* clear the waiting data anyway */ | 66 | for (; i < size; i++) { /* clear the waiting data anyway */ |
73 | status = inb(chip->vendor->base + 1); | 67 | status = atmel_getb(chip, 1); |
74 | if ((status & ATML_STATUS_DATA_AVAIL) == 0) { | 68 | if ((status & ATML_STATUS_DATA_AVAIL) == 0) { |
75 | dev_err(chip->dev, | 69 | dev_err(chip->dev, |
76 | "error reading data\n"); | 70 | "error reading data\n"); |
@@ -82,17 +76,17 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) | |||
82 | 76 | ||
83 | /* read all the data available */ | 77 | /* read all the data available */ |
84 | for (; i < size; i++) { | 78 | for (; i < size; i++) { |
85 | status = inb(chip->vendor->base + 1); | 79 | status = atmel_getb(chip, 1); |
86 | if ((status & ATML_STATUS_DATA_AVAIL) == 0) { | 80 | if ((status & ATML_STATUS_DATA_AVAIL) == 0) { |
87 | dev_err(chip->dev, | 81 | dev_err(chip->dev, |
88 | "error reading data\n"); | 82 | "error reading data\n"); |
89 | return -EIO; | 83 | return -EIO; |
90 | } | 84 | } |
91 | *buf++ = inb(chip->vendor->base); | 85 | *buf++ = atmel_getb(chip, 0); |
92 | } | 86 | } |
93 | 87 | ||
94 | /* make sure data available is gone */ | 88 | /* make sure data available is gone */ |
95 | status = inb(chip->vendor->base + 1); | 89 | status = atmel_getb(chip, 1); |
96 | if (status & ATML_STATUS_DATA_AVAIL) { | 90 | if (status & ATML_STATUS_DATA_AVAIL) { |
97 | dev_err(chip->dev, "data available is stuck\n"); | 91 | dev_err(chip->dev, "data available is stuck\n"); |
98 | return -EIO; | 92 | return -EIO; |
@@ -108,7 +102,7 @@ static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count) | |||
108 | dev_dbg(chip->dev, "tpm_atml_send:\n"); | 102 | dev_dbg(chip->dev, "tpm_atml_send:\n"); |
109 | for (i = 0; i < count; i++) { | 103 | for (i = 0; i < count; i++) { |
110 | dev_dbg(chip->dev, "%d 0x%x(%d)\n", i, buf[i], buf[i]); | 104 | dev_dbg(chip->dev, "%d 0x%x(%d)\n", i, buf[i], buf[i]); |
111 | outb(buf[i], chip->vendor->base); | 105 | atmel_putb(buf[i], chip, 0); |
112 | } | 106 | } |
113 | 107 | ||
114 | return count; | 108 | return count; |
@@ -116,12 +110,12 @@ static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count) | |||
116 | 110 | ||
117 | static void tpm_atml_cancel(struct tpm_chip *chip) | 111 | static void tpm_atml_cancel(struct tpm_chip *chip) |
118 | { | 112 | { |
119 | outb(ATML_STATUS_ABORT, chip->vendor->base + 1); | 113 | atmel_putb(ATML_STATUS_ABORT, chip, 1); |
120 | } | 114 | } |
121 | 115 | ||
122 | static u8 tpm_atml_status(struct tpm_chip *chip) | 116 | static u8 tpm_atml_status(struct tpm_chip *chip) |
123 | { | 117 | { |
124 | return inb(chip->vendor->base + 1); | 118 | return atmel_getb(chip, 1); |
125 | } | 119 | } |
126 | 120 | ||
127 | static struct file_operations atmel_ops = { | 121 | static struct file_operations atmel_ops = { |
@@ -162,12 +156,16 @@ static struct tpm_vendor_specific tpm_atmel = { | |||
162 | 156 | ||
163 | static struct platform_device *pdev; | 157 | static struct platform_device *pdev; |
164 | 158 | ||
165 | static void __devexit tpm_atml_remove(struct device *dev) | 159 | static void atml_plat_remove(void) |
166 | { | 160 | { |
167 | struct tpm_chip *chip = dev_get_drvdata(dev); | 161 | struct tpm_chip *chip = dev_get_drvdata(&pdev->dev); |
162 | |||
168 | if (chip) { | 163 | if (chip) { |
169 | release_region(chip->vendor->base, 2); | 164 | if (chip->vendor->have_region) |
165 | atmel_release_region(chip->vendor->base, chip->vendor->region_size); | ||
166 | atmel_put_base_addr(chip->vendor); | ||
170 | tpm_remove_hardware(chip->dev); | 167 | tpm_remove_hardware(chip->dev); |
168 | platform_device_unregister(pdev); | ||
171 | } | 169 | } |
172 | } | 170 | } |
173 | 171 | ||
@@ -182,72 +180,40 @@ static struct device_driver atml_drv = { | |||
182 | static int __init init_atmel(void) | 180 | static int __init init_atmel(void) |
183 | { | 181 | { |
184 | int rc = 0; | 182 | int rc = 0; |
185 | int lo, hi; | ||
186 | 183 | ||
187 | driver_register(&atml_drv); | 184 | driver_register(&atml_drv); |
188 | 185 | ||
189 | lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO); | 186 | if (atmel_get_base_addr(&tpm_atmel) != 0) { |
190 | hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI); | 187 | rc = -ENODEV; |
191 | 188 | goto err_unreg_drv; | |
192 | tpm_atmel.base = (hi<<8)|lo; | ||
193 | |||
194 | /* verify that it is an Atmel part */ | ||
195 | if (tpm_read_index(TPM_ADDR, 4) != 'A' || tpm_read_index(TPM_ADDR, 5) != 'T' | ||
196 | || tpm_read_index(TPM_ADDR, 6) != 'M' || tpm_read_index(TPM_ADDR, 7) != 'L') { | ||
197 | return -ENODEV; | ||
198 | } | ||
199 | |||
200 | /* verify chip version number is 1.1 */ | ||
201 | if ( (tpm_read_index(TPM_ADDR, 0x00) != 0x01) || | ||
202 | (tpm_read_index(TPM_ADDR, 0x01) != 0x01 )) | ||
203 | return -ENODEV; | ||
204 | |||
205 | pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL); | ||
206 | if ( !pdev ) | ||
207 | return -ENOMEM; | ||
208 | |||
209 | pdev->name = "tpm_atmel0"; | ||
210 | pdev->id = -1; | ||
211 | pdev->num_resources = 0; | ||
212 | pdev->dev.release = tpm_atml_remove; | ||
213 | pdev->dev.driver = &atml_drv; | ||
214 | |||
215 | if ((rc = platform_device_register(pdev)) < 0) { | ||
216 | kfree(pdev); | ||
217 | pdev = NULL; | ||
218 | return rc; | ||
219 | } | 189 | } |
220 | 190 | ||
221 | if (request_region(tpm_atmel.base, 2, "tpm_atmel0") == NULL ) { | 191 | tpm_atmel.have_region = (atmel_request_region( tpm_atmel.base, tpm_atmel.region_size, "tpm_atmel0") == NULL) ? 0 : 1; |
222 | platform_device_unregister(pdev); | ||
223 | kfree(pdev); | ||
224 | pdev = NULL; | ||
225 | return -EBUSY; | ||
226 | } | ||
227 | 192 | ||
228 | if ((rc = tpm_register_hardware(&pdev->dev, &tpm_atmel)) < 0) { | 193 | if (IS_ERR(pdev = platform_device_register_simple("tpm_atmel", -1, NULL, 0 ))) { |
229 | release_region(tpm_atmel.base, 2); | 194 | rc = PTR_ERR(pdev); |
230 | platform_device_unregister(pdev); | 195 | goto err_rel_reg; |
231 | kfree(pdev); | ||
232 | pdev = NULL; | ||
233 | return rc; | ||
234 | } | 196 | } |
235 | 197 | ||
236 | dev_info(&pdev->dev, "Atmel TPM 1.1, Base Address: 0x%x\n", | 198 | if ((rc = tpm_register_hardware(&pdev->dev, &tpm_atmel)) < 0) |
237 | tpm_atmel.base); | 199 | goto err_unreg_dev; |
238 | return 0; | 200 | return 0; |
201 | |||
202 | err_unreg_dev: | ||
203 | platform_device_unregister(pdev); | ||
204 | err_rel_reg: | ||
205 | if (tpm_atmel.have_region) | ||
206 | atmel_release_region(tpm_atmel.base, tpm_atmel.region_size); | ||
207 | atmel_put_base_addr(&tpm_atmel); | ||
208 | err_unreg_drv: | ||
209 | driver_unregister(&atml_drv); | ||
210 | return rc; | ||
239 | } | 211 | } |
240 | 212 | ||
241 | static void __exit cleanup_atmel(void) | 213 | static void __exit cleanup_atmel(void) |
242 | { | 214 | { |
243 | if (pdev) { | ||
244 | tpm_atml_remove(&pdev->dev); | ||
245 | platform_device_unregister(pdev); | ||
246 | kfree(pdev); | ||
247 | pdev = NULL; | ||
248 | } | ||
249 | |||
250 | driver_unregister(&atml_drv); | 215 | driver_unregister(&atml_drv); |
216 | atml_plat_remove(); | ||
251 | } | 217 | } |
252 | 218 | ||
253 | module_init(init_atmel); | 219 | module_init(init_atmel); |
diff --git a/drivers/char/tpm/tpm_atmel.h b/drivers/char/tpm/tpm_atmel.h new file mode 100644 index 000000000000..3c5b9a8d1c49 --- /dev/null +++ b/drivers/char/tpm/tpm_atmel.h | |||
@@ -0,0 +1,129 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005 IBM Corporation | ||
3 | * | ||
4 | * Authors: | ||
5 | * Kylene Hall <kjhall@us.ibm.com> | ||
6 | * | ||
7 | * Maintained by: <tpmdd_devel@lists.sourceforge.net> | ||
8 | * | ||
9 | * Device driver for TCG/TCPA TPM (trusted platform module). | ||
10 | * Specifications at www.trustedcomputinggroup.org | ||
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. | ||
16 | * | ||
17 | * These difference are required on power because the device must be | ||
18 | * discovered through the device tree and iomap must be used to get | ||
19 | * around the need for holes in the io_page_mask. This does not happen | ||
20 | * automatically because the tpm is not a normal pci device and lives | ||
21 | * under the root node. | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifdef CONFIG_PPC64 | ||
26 | #define atmel_getb(chip, offset) readb(chip->vendor->iobase + offset); | ||
27 | #define atmel_putb(val, chip, offset) writeb(val, chip->vendor->iobase + offset) | ||
28 | #define atmel_request_region request_mem_region | ||
29 | #define atmel_release_region release_mem_region | ||
30 | static inline void atmel_put_base_addr(struct tpm_vendor_specific *vendor) | ||
31 | { | ||
32 | iounmap(vendor->iobase); | ||
33 | } | ||
34 | |||
35 | static int atmel_get_base_addr(struct tpm_vendor_specific *vendor) | ||
36 | { | ||
37 | struct device_node *dn; | ||
38 | unsigned long address, size; | ||
39 | unsigned int *reg; | ||
40 | int reglen; | ||
41 | int naddrc; | ||
42 | int nsizec; | ||
43 | |||
44 | dn = of_find_node_by_name(NULL, "tpm"); | ||
45 | |||
46 | if (!dn) | ||
47 | return 1; | ||
48 | |||
49 | if (!device_is_compatible(dn, "AT97SC3201")) { | ||
50 | of_node_put(dn); | ||
51 | return 1; | ||
52 | } | ||
53 | |||
54 | reg = (unsigned int *) get_property(dn, "reg", ®len); | ||
55 | naddrc = prom_n_addr_cells(dn); | ||
56 | nsizec = prom_n_size_cells(dn); | ||
57 | |||
58 | of_node_put(dn); | ||
59 | |||
60 | |||
61 | if (naddrc == 2) | ||
62 | address = ((unsigned long) reg[0] << 32) | reg[1]; | ||
63 | else | ||
64 | address = reg[0]; | ||
65 | |||
66 | if (nsizec == 2) | ||
67 | size = | ||
68 | ((unsigned long) reg[naddrc] << 32) | reg[naddrc + 1]; | ||
69 | else | ||
70 | size = reg[naddrc]; | ||
71 | |||
72 | vendor->base = address; | ||
73 | vendor->region_size = size; | ||
74 | vendor->iobase = ioremap(address, size); | ||
75 | return 0; | ||
76 | } | ||
77 | #else | ||
78 | #define atmel_getb(chip, offset) inb(chip->vendor->base + offset) | ||
79 | #define atmel_putb(val, chip, offset) outb(val, chip->vendor->base + offset) | ||
80 | #define atmel_request_region request_region | ||
81 | #define atmel_release_region release_region | ||
82 | /* Atmel definitions */ | ||
83 | enum tpm_atmel_addr { | ||
84 | TPM_ATMEL_BASE_ADDR_LO = 0x08, | ||
85 | TPM_ATMEL_BASE_ADDR_HI = 0x09 | ||
86 | }; | ||
87 | |||
88 | /* Verify this is a 1.1 Atmel TPM */ | ||
89 | static int atmel_verify_tpm11(void) | ||
90 | { | ||
91 | |||
92 | /* verify that it is an Atmel part */ | ||
93 | if (tpm_read_index(TPM_ADDR, 4) != 'A' || | ||
94 | tpm_read_index(TPM_ADDR, 5) != 'T' || | ||
95 | tpm_read_index(TPM_ADDR, 6) != 'M' || | ||
96 | tpm_read_index(TPM_ADDR, 7) != 'L') | ||
97 | return 1; | ||
98 | |||
99 | /* query chip for its version number */ | ||
100 | if (tpm_read_index(TPM_ADDR, 0x00) != 1 || | ||
101 | tpm_read_index(TPM_ADDR, 0x01) != 1) | ||
102 | return 1; | ||
103 | |||
104 | /* This is an atmel supported part */ | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static inline void atmel_put_base_addr(struct tpm_vendor_specific *vendor) | ||
109 | { | ||
110 | } | ||
111 | |||
112 | /* Determine where to talk to device */ | ||
113 | static unsigned long atmel_get_base_addr(struct tpm_vendor_specific | ||
114 | *vendor) | ||
115 | { | ||
116 | int lo, hi; | ||
117 | |||
118 | if (atmel_verify_tpm11() != 0) | ||
119 | return 1; | ||
120 | |||
121 | lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO); | ||
122 | hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI); | ||
123 | |||
124 | vendor->base = (hi << 8) | lo; | ||
125 | vendor->region_size = 2; | ||
126 | |||
127 | return 0; | ||
128 | } | ||
129 | #endif | ||