11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Copyright (C) 2004 IBM Corporation 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Authors: 51da177e4SLinus Torvalds * Leendert van Doorn <leendert@watson.ibm.com> 61da177e4SLinus Torvalds * Dave Safford <safford@watson.ibm.com> 71da177e4SLinus Torvalds * Reiner Sailer <sailer@watson.ibm.com> 81da177e4SLinus Torvalds * Kylene Hall <kjhall@us.ibm.com> 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * Maintained by: <tpmdd_devel@lists.sourceforge.net> 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * Device driver for TCG/TCPA TPM (trusted platform module). 131da177e4SLinus Torvalds * Specifications at www.trustedcomputinggroup.org 141da177e4SLinus Torvalds * 151da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 161da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License as 171da177e4SLinus Torvalds * published by the Free Software Foundation, version 2 of the 181da177e4SLinus Torvalds * License. 191da177e4SLinus Torvalds * 201da177e4SLinus Torvalds */ 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds #include "tpm.h" 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds /* Atmel definitions */ 251da177e4SLinus Torvalds #define TPM_ATML_BASE 0x400 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds /* write status bits */ 281da177e4SLinus Torvalds #define ATML_STATUS_ABORT 0x01 291da177e4SLinus Torvalds #define ATML_STATUS_LASTBYTE 0x04 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds /* read status bits */ 321da177e4SLinus Torvalds #define ATML_STATUS_BUSY 0x01 331da177e4SLinus Torvalds #define ATML_STATUS_DATA_AVAIL 0x02 341da177e4SLinus Torvalds #define ATML_STATUS_REWRITE 0x04 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds static int tpm_atml_recv(struct tpm_chip *chip, u8 * buf, size_t count) 381da177e4SLinus Torvalds { 391da177e4SLinus Torvalds u8 status, *hdr = buf; 401da177e4SLinus Torvalds u32 size; 411da177e4SLinus Torvalds int i; 421da177e4SLinus Torvalds __be32 *native_size; 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds /* start reading header */ 451da177e4SLinus Torvalds if (count < 6) 461da177e4SLinus Torvalds return -EIO; 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds for (i = 0; i < 6; i++) { 491da177e4SLinus Torvalds status = inb(chip->vendor->base + 1); 501da177e4SLinus Torvalds if ((status & ATML_STATUS_DATA_AVAIL) == 0) { 511da177e4SLinus Torvalds dev_err(&chip->pci_dev->dev, 521da177e4SLinus Torvalds "error reading header\n"); 531da177e4SLinus Torvalds return -EIO; 541da177e4SLinus Torvalds } 551da177e4SLinus Torvalds *buf++ = inb(chip->vendor->base); 561da177e4SLinus Torvalds } 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds /* size of the data received */ 591da177e4SLinus Torvalds native_size = (__force __be32 *) (hdr + 2); 601da177e4SLinus Torvalds size = be32_to_cpu(*native_size); 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds if (count < size) { 631da177e4SLinus Torvalds dev_err(&chip->pci_dev->dev, 641da177e4SLinus Torvalds "Recv size(%d) less than available space\n", size); 651da177e4SLinus Torvalds for (; i < size; i++) { /* clear the waiting data anyway */ 661da177e4SLinus Torvalds status = inb(chip->vendor->base + 1); 671da177e4SLinus Torvalds if ((status & ATML_STATUS_DATA_AVAIL) == 0) { 681da177e4SLinus Torvalds dev_err(&chip->pci_dev->dev, 691da177e4SLinus Torvalds "error reading data\n"); 701da177e4SLinus Torvalds return -EIO; 711da177e4SLinus Torvalds } 721da177e4SLinus Torvalds } 731da177e4SLinus Torvalds return -EIO; 741da177e4SLinus Torvalds } 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds /* read all the data available */ 771da177e4SLinus Torvalds for (; i < size; i++) { 781da177e4SLinus Torvalds status = inb(chip->vendor->base + 1); 791da177e4SLinus Torvalds if ((status & ATML_STATUS_DATA_AVAIL) == 0) { 801da177e4SLinus Torvalds dev_err(&chip->pci_dev->dev, 811da177e4SLinus Torvalds "error reading data\n"); 821da177e4SLinus Torvalds return -EIO; 831da177e4SLinus Torvalds } 841da177e4SLinus Torvalds *buf++ = inb(chip->vendor->base); 851da177e4SLinus Torvalds } 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds /* make sure data available is gone */ 881da177e4SLinus Torvalds status = inb(chip->vendor->base + 1); 891da177e4SLinus Torvalds if (status & ATML_STATUS_DATA_AVAIL) { 901da177e4SLinus Torvalds dev_err(&chip->pci_dev->dev, "data available is stuck\n"); 911da177e4SLinus Torvalds return -EIO; 921da177e4SLinus Torvalds } 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds return size; 951da177e4SLinus Torvalds } 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds static int tpm_atml_send(struct tpm_chip *chip, u8 * buf, size_t count) 981da177e4SLinus Torvalds { 991da177e4SLinus Torvalds int i; 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds dev_dbg(&chip->pci_dev->dev, "tpm_atml_send: "); 1021da177e4SLinus Torvalds for (i = 0; i < count; i++) { 1031da177e4SLinus Torvalds dev_dbg(&chip->pci_dev->dev, "0x%x(%d) ", buf[i], buf[i]); 1041da177e4SLinus Torvalds outb(buf[i], chip->vendor->base); 1051da177e4SLinus Torvalds } 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds return count; 1081da177e4SLinus Torvalds } 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds static void tpm_atml_cancel(struct tpm_chip *chip) 1111da177e4SLinus Torvalds { 1121da177e4SLinus Torvalds outb(ATML_STATUS_ABORT, chip->vendor->base + 1); 1131da177e4SLinus Torvalds } 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds static struct file_operations atmel_ops = { 1161da177e4SLinus Torvalds .owner = THIS_MODULE, 1171da177e4SLinus Torvalds .llseek = no_llseek, 1181da177e4SLinus Torvalds .open = tpm_open, 1191da177e4SLinus Torvalds .read = tpm_read, 1201da177e4SLinus Torvalds .write = tpm_write, 1211da177e4SLinus Torvalds .release = tpm_release, 1221da177e4SLinus Torvalds }; 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds static struct tpm_vendor_specific tpm_atmel = { 1251da177e4SLinus Torvalds .recv = tpm_atml_recv, 1261da177e4SLinus Torvalds .send = tpm_atml_send, 1271da177e4SLinus Torvalds .cancel = tpm_atml_cancel, 1281da177e4SLinus Torvalds .req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL, 1291da177e4SLinus Torvalds .req_complete_val = ATML_STATUS_DATA_AVAIL, 1301da177e4SLinus Torvalds .base = TPM_ATML_BASE, 1311da177e4SLinus Torvalds .miscdev = { .fops = &atmel_ops, }, 1321da177e4SLinus Torvalds }; 1331da177e4SLinus Torvalds 1341da177e4SLinus Torvalds static int __devinit tpm_atml_init(struct pci_dev *pci_dev, 1351da177e4SLinus Torvalds const struct pci_device_id *pci_id) 1361da177e4SLinus Torvalds { 1371da177e4SLinus Torvalds u8 version[4]; 1381da177e4SLinus Torvalds int rc = 0; 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds if (pci_enable_device(pci_dev)) 1411da177e4SLinus Torvalds return -EIO; 1421da177e4SLinus Torvalds 1431da177e4SLinus Torvalds if (tpm_lpc_bus_init(pci_dev, TPM_ATML_BASE)) { 1441da177e4SLinus Torvalds rc = -ENODEV; 1451da177e4SLinus Torvalds goto out_err; 1461da177e4SLinus Torvalds } 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds /* verify that it is an Atmel part */ 1491da177e4SLinus Torvalds if (tpm_read_index(4) != 'A' || tpm_read_index(5) != 'T' 1501da177e4SLinus Torvalds || tpm_read_index(6) != 'M' || tpm_read_index(7) != 'L') { 1511da177e4SLinus Torvalds rc = -ENODEV; 1521da177e4SLinus Torvalds goto out_err; 1531da177e4SLinus Torvalds } 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds /* query chip for its version number */ 1561da177e4SLinus Torvalds if ((version[0] = tpm_read_index(0x00)) != 0xFF) { 1571da177e4SLinus Torvalds version[1] = tpm_read_index(0x01); 1581da177e4SLinus Torvalds version[2] = tpm_read_index(0x02); 1591da177e4SLinus Torvalds version[3] = tpm_read_index(0x03); 1601da177e4SLinus Torvalds } else { 1611da177e4SLinus Torvalds dev_info(&pci_dev->dev, "version query failed\n"); 1621da177e4SLinus Torvalds rc = -ENODEV; 1631da177e4SLinus Torvalds goto out_err; 1641da177e4SLinus Torvalds } 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds if ((rc = tpm_register_hardware(pci_dev, &tpm_atmel)) < 0) 1671da177e4SLinus Torvalds goto out_err; 1681da177e4SLinus Torvalds 1691da177e4SLinus Torvalds dev_info(&pci_dev->dev, 1701da177e4SLinus Torvalds "Atmel TPM version %d.%d.%d.%d\n", version[0], version[1], 1711da177e4SLinus Torvalds version[2], version[3]); 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds return 0; 1741da177e4SLinus Torvalds out_err: 1751da177e4SLinus Torvalds pci_disable_device(pci_dev); 1761da177e4SLinus Torvalds return rc; 1771da177e4SLinus Torvalds } 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds static struct pci_device_id tpm_pci_tbl[] __devinitdata = { 1801da177e4SLinus Torvalds {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0)}, 1811da177e4SLinus Torvalds {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12)}, 1821da177e4SLinus Torvalds {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)}, 1831da177e4SLinus Torvalds {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)}, 1841da177e4SLinus Torvalds {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)}, 1851da177e4SLinus Torvalds {PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)}, 1861da177e4SLinus Torvalds {0,} 1871da177e4SLinus Torvalds }; 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci, tpm_pci_tbl); 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds static struct pci_driver atmel_pci_driver = { 1921da177e4SLinus Torvalds .name = "tpm_atmel", 1931da177e4SLinus Torvalds .id_table = tpm_pci_tbl, 1941da177e4SLinus Torvalds .probe = tpm_atml_init, 1951da177e4SLinus Torvalds .remove = __devexit_p(tpm_remove), 1961da177e4SLinus Torvalds .suspend = tpm_pm_suspend, 1971da177e4SLinus Torvalds .resume = tpm_pm_resume, 1981da177e4SLinus Torvalds }; 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds static int __init init_atmel(void) 2011da177e4SLinus Torvalds { 2021da177e4SLinus Torvalds return pci_register_driver(&atmel_pci_driver); 2031da177e4SLinus Torvalds } 2041da177e4SLinus Torvalds 2051da177e4SLinus Torvalds static void __exit cleanup_atmel(void) 2061da177e4SLinus Torvalds { 2071da177e4SLinus Torvalds pci_unregister_driver(&atmel_pci_driver); 2081da177e4SLinus Torvalds } 2091da177e4SLinus Torvalds 2101da177e4SLinus Torvalds module_init(init_atmel); 2111da177e4SLinus Torvalds module_exit(cleanup_atmel); 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)"); 2141da177e4SLinus Torvalds MODULE_DESCRIPTION("TPM Driver"); 2151da177e4SLinus Torvalds MODULE_VERSION("2.0"); 2161da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 217