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 struct file_operations atmel_ops = { 122 .owner = THIS_MODULE, 123 .llseek = no_llseek, 124 .open = tpm_open, 125 .read = tpm_read, 126 .write = tpm_write, 127 .release = tpm_release, 128 }; 129 130 static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); 131 static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); 132 static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); 133 static DEVICE_ATTR(cancel, S_IWUSR |S_IWGRP, NULL, tpm_store_cancel); 134 135 static struct attribute* atmel_attrs[] = { 136 &dev_attr_pubek.attr, 137 &dev_attr_pcrs.attr, 138 &dev_attr_caps.attr, 139 &dev_attr_cancel.attr, 140 0, 141 }; 142 143 static struct attribute_group atmel_attr_grp = { .attrs = atmel_attrs }; 144 145 static struct tpm_vendor_specific tpm_atmel = { 146 .recv = tpm_atml_recv, 147 .send = tpm_atml_send, 148 .cancel = tpm_atml_cancel, 149 .req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL, 150 .req_complete_val = ATML_STATUS_DATA_AVAIL, 151 .req_canceled = ATML_STATUS_READY, 152 .attr_group = &atmel_attr_grp, 153 .miscdev = { .fops = &atmel_ops, }, 154 }; 155 156 static int __devinit tpm_atml_init(struct pci_dev *pci_dev, 157 const struct pci_device_id *pci_id) 158 { 159 u8 version[4]; 160 int rc = 0; 161 int lo, hi; 162 163 if (pci_enable_device(pci_dev)) 164 return -EIO; 165 166 lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO); 167 hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI); 168 169 tpm_atmel.base = (hi<<8)|lo; 170 dev_dbg( &pci_dev->dev, "Operating with base: 0x%x\n", tpm_atmel.base); 171 172 /* verify that it is an Atmel part */ 173 if (tpm_read_index(TPM_ADDR, 4) != 'A' || tpm_read_index(TPM_ADDR, 5) != 'T' 174 || tpm_read_index(TPM_ADDR, 6) != 'M' || tpm_read_index(TPM_ADDR, 7) != 'L') { 175 rc = -ENODEV; 176 goto out_err; 177 } 178 179 /* query chip for its version number */ 180 if ((version[0] = tpm_read_index(TPM_ADDR, 0x00)) != 0xFF) { 181 version[1] = tpm_read_index(TPM_ADDR, 0x01); 182 version[2] = tpm_read_index(TPM_ADDR, 0x02); 183 version[3] = tpm_read_index(TPM_ADDR, 0x03); 184 } else { 185 dev_info(&pci_dev->dev, "version query failed\n"); 186 rc = -ENODEV; 187 goto out_err; 188 } 189 190 if ((rc = tpm_register_hardware(pci_dev, &tpm_atmel)) < 0) 191 goto out_err; 192 193 dev_info(&pci_dev->dev, 194 "Atmel TPM version %d.%d.%d.%d\n", version[0], version[1], 195 version[2], version[3]); 196 197 return 0; 198 out_err: 199 pci_disable_device(pci_dev); 200 return rc; 201 } 202 203 static struct pci_device_id tpm_pci_tbl[] __devinitdata = { 204 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0)}, 205 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12)}, 206 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)}, 207 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)}, 208 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)}, 209 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)}, 210 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)}, 211 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)}, 212 {PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)}, 213 {PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6LPC)}, 214 {0,} 215 }; 216 217 MODULE_DEVICE_TABLE(pci, tpm_pci_tbl); 218 219 static struct pci_driver atmel_pci_driver = { 220 .name = "tpm_atmel", 221 .id_table = tpm_pci_tbl, 222 .probe = tpm_atml_init, 223 .remove = __devexit_p(tpm_remove), 224 .suspend = tpm_pm_suspend, 225 .resume = tpm_pm_resume, 226 }; 227 228 static int __init init_atmel(void) 229 { 230 return pci_register_driver(&atmel_pci_driver); 231 } 232 233 static void __exit cleanup_atmel(void) 234 { 235 pci_unregister_driver(&atmel_pci_driver); 236 } 237 238 module_init(init_atmel); 239 module_exit(cleanup_atmel); 240 241 MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)"); 242 MODULE_DESCRIPTION("TPM Driver"); 243 MODULE_VERSION("2.0"); 244 MODULE_LICENSE("GPL"); 245