1 /* 2 * Copyright (C) 2004 IBM Corporation 3 * 4 * Authors: 5 * Leendert van Doorn <leendert@watson.ibm.com> 6 * Dave Safford <safford@watson.ibm.com> 7 * Reiner Sailer <sailer@watson.ibm.com> 8 * Kylene Hall <kjhall@us.ibm.com> 9 * 10 * Maintained by: <tpmdd_devel@lists.sourceforge.net> 11 * 12 * Device driver for TCG/TCPA TPM (trusted platform module). 13 * Specifications at www.trustedcomputinggroup.org 14 * 15 * This program is free software; you can redistribute it and/or 16 * modify it under the terms of the GNU General Public License as 17 * published by the Free Software Foundation, version 2 of the 18 * License. 19 * 20 */ 21 22 #include "tpm.h" 23 24 /* Atmel definitions */ 25 enum tpm_atmel_addr { 26 TPM_ATMEL_BASE_ADDR_LO = 0x08, 27 TPM_ATMEL_BASE_ADDR_HI = 0x09 28 }; 29 30 /* write status bits */ 31 enum tpm_atmel_write_status { 32 ATML_STATUS_ABORT = 0x01, 33 ATML_STATUS_LASTBYTE = 0x04 34 }; 35 /* read status bits */ 36 enum tpm_atmel_read_status { 37 ATML_STATUS_BUSY = 0x01, 38 ATML_STATUS_DATA_AVAIL = 0x02, 39 ATML_STATUS_REWRITE = 0x04, 40 ATML_STATUS_READY = 0x08 41 }; 42 43 static int tpm_atml_recv(struct tpm_chip *chip, u8 * buf, size_t count) 44 { 45 u8 status, *hdr = buf; 46 u32 size; 47 int i; 48 __be32 *native_size; 49 50 /* start reading header */ 51 if (count < 6) 52 return -EIO; 53 54 for (i = 0; i < 6; i++) { 55 status = inb(chip->vendor->base + 1); 56 if ((status & ATML_STATUS_DATA_AVAIL) == 0) { 57 dev_err(&chip->pci_dev->dev, 58 "error reading header\n"); 59 return -EIO; 60 } 61 *buf++ = inb(chip->vendor->base); 62 } 63 64 /* size of the data received */ 65 native_size = (__force __be32 *) (hdr + 2); 66 size = be32_to_cpu(*native_size); 67 68 if (count < size) { 69 dev_err(&chip->pci_dev->dev, 70 "Recv size(%d) less than available space\n", size); 71 for (; i < size; i++) { /* clear the waiting data anyway */ 72 status = inb(chip->vendor->base + 1); 73 if ((status & ATML_STATUS_DATA_AVAIL) == 0) { 74 dev_err(&chip->pci_dev->dev, 75 "error reading data\n"); 76 return -EIO; 77 } 78 } 79 return -EIO; 80 } 81 82 /* read all the data available */ 83 for (; i < size; i++) { 84 status = inb(chip->vendor->base + 1); 85 if ((status & ATML_STATUS_DATA_AVAIL) == 0) { 86 dev_err(&chip->pci_dev->dev, 87 "error reading data\n"); 88 return -EIO; 89 } 90 *buf++ = inb(chip->vendor->base); 91 } 92 93 /* make sure data available is gone */ 94 status = inb(chip->vendor->base + 1); 95 if (status & ATML_STATUS_DATA_AVAIL) { 96 dev_err(&chip->pci_dev->dev, "data available is stuck\n"); 97 return -EIO; 98 } 99 100 return size; 101 } 102 103 static int tpm_atml_send(struct tpm_chip *chip, u8 * buf, size_t count) 104 { 105 int i; 106 107 dev_dbg(&chip->pci_dev->dev, "tpm_atml_send: "); 108 for (i = 0; i < count; i++) { 109 dev_dbg(&chip->pci_dev->dev, "0x%x(%d) ", buf[i], buf[i]); 110 outb(buf[i], chip->vendor->base); 111 } 112 113 return count; 114 } 115 116 static void tpm_atml_cancel(struct tpm_chip *chip) 117 { 118 outb(ATML_STATUS_ABORT, chip->vendor->base + 1); 119 } 120 121 static u8 tpm_atml_status(struct tpm_chip *chip) 122 { 123 return inb(chip->vendor->base + 1); 124 } 125 126 static struct file_operations atmel_ops = { 127 .owner = THIS_MODULE, 128 .llseek = no_llseek, 129 .open = tpm_open, 130 .read = tpm_read, 131 .write = tpm_write, 132 .release = tpm_release, 133 }; 134 135 static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); 136 static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); 137 static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); 138 static DEVICE_ATTR(cancel, S_IWUSR |S_IWGRP, NULL, tpm_store_cancel); 139 140 static struct attribute* atmel_attrs[] = { 141 &dev_attr_pubek.attr, 142 &dev_attr_pcrs.attr, 143 &dev_attr_caps.attr, 144 &dev_attr_cancel.attr, 145 0, 146 }; 147 148 static struct attribute_group atmel_attr_grp = { .attrs = atmel_attrs }; 149 150 static struct tpm_vendor_specific tpm_atmel = { 151 .recv = tpm_atml_recv, 152 .send = tpm_atml_send, 153 .cancel = tpm_atml_cancel, 154 .status = tpm_atml_status, 155 .req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL, 156 .req_complete_val = ATML_STATUS_DATA_AVAIL, 157 .req_canceled = ATML_STATUS_READY, 158 .attr_group = &atmel_attr_grp, 159 .miscdev = { .fops = &atmel_ops, }, 160 }; 161 162 static int __devinit tpm_atml_init(struct pci_dev *pci_dev, 163 const struct pci_device_id *pci_id) 164 { 165 u8 version[4]; 166 int rc = 0; 167 int lo, hi; 168 169 if (pci_enable_device(pci_dev)) 170 return -EIO; 171 172 lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO); 173 hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI); 174 175 tpm_atmel.base = (hi<<8)|lo; 176 dev_dbg( &pci_dev->dev, "Operating with base: 0x%x\n", tpm_atmel.base); 177 178 /* verify that it is an Atmel part */ 179 if (tpm_read_index(TPM_ADDR, 4) != 'A' || tpm_read_index(TPM_ADDR, 5) != 'T' 180 || tpm_read_index(TPM_ADDR, 6) != 'M' || tpm_read_index(TPM_ADDR, 7) != 'L') { 181 rc = -ENODEV; 182 goto out_err; 183 } 184 185 /* query chip for its version number */ 186 if ((version[0] = tpm_read_index(TPM_ADDR, 0x00)) != 0xFF) { 187 version[1] = tpm_read_index(TPM_ADDR, 0x01); 188 version[2] = tpm_read_index(TPM_ADDR, 0x02); 189 version[3] = tpm_read_index(TPM_ADDR, 0x03); 190 } else { 191 dev_info(&pci_dev->dev, "version query failed\n"); 192 rc = -ENODEV; 193 goto out_err; 194 } 195 196 if ((rc = tpm_register_hardware(pci_dev, &tpm_atmel)) < 0) 197 goto out_err; 198 199 dev_info(&pci_dev->dev, 200 "Atmel TPM version %d.%d.%d.%d\n", version[0], version[1], 201 version[2], version[3]); 202 203 return 0; 204 out_err: 205 pci_disable_device(pci_dev); 206 return rc; 207 } 208 209 static struct pci_device_id tpm_pci_tbl[] __devinitdata = { 210 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0)}, 211 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12)}, 212 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)}, 213 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)}, 214 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)}, 215 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)}, 216 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)}, 217 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)}, 218 {PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)}, 219 {PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6LPC)}, 220 {0,} 221 }; 222 223 MODULE_DEVICE_TABLE(pci, tpm_pci_tbl); 224 225 static struct pci_driver atmel_pci_driver = { 226 .name = "tpm_atmel", 227 .id_table = tpm_pci_tbl, 228 .probe = tpm_atml_init, 229 .remove = __devexit_p(tpm_remove), 230 .suspend = tpm_pm_suspend, 231 .resume = tpm_pm_resume, 232 }; 233 234 static int __init init_atmel(void) 235 { 236 return pci_register_driver(&atmel_pci_driver); 237 } 238 239 static void __exit cleanup_atmel(void) 240 { 241 pci_unregister_driver(&atmel_pci_driver); 242 } 243 244 module_init(init_atmel); 245 module_exit(cleanup_atmel); 246 247 MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)"); 248 MODULE_DESCRIPTION("TPM Driver"); 249 MODULE_VERSION("2.0"); 250 MODULE_LICENSE("GPL"); 251