1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2004 IBM Corporation 4 * 5 * Authors: 6 * Leendert van Doorn <leendert@watson.ibm.com> 7 * Dave Safford <safford@watson.ibm.com> 8 * Reiner Sailer <sailer@watson.ibm.com> 9 * Kylene Hall <kjhall@us.ibm.com> 10 * 11 * Maintained by: <tpmdd-devel@lists.sourceforge.net> 12 * 13 * Device driver for TCG/TCPA TPM (trusted platform module). 14 * Specifications at www.trustedcomputinggroup.org 15 */ 16 17 #include "tpm.h" 18 19 struct tpm_atmel_priv { 20 int region_size; 21 int have_region; 22 unsigned long base; 23 void __iomem *iobase; 24 }; 25 26 #define atmel_getb(chip, offset) inb(atmel_get_priv(chip)->base + (offset)) 27 #define atmel_putb(val, chip, offset) \ 28 outb(val, atmel_get_priv(chip)->base + (offset)) 29 #define atmel_request_region request_region 30 #define atmel_release_region release_region 31 /* Atmel definitions */ 32 enum tpm_atmel_addr { 33 TPM_ATMEL_BASE_ADDR_LO = 0x08, 34 TPM_ATMEL_BASE_ADDR_HI = 0x09 35 }; 36 37 static inline int tpm_read_index(int base, int index) 38 { 39 outb(index, base); 40 return inb(base + 1) & 0xFF; 41 } 42 43 /* Verify this is a 1.1 Atmel TPM */ 44 static int atmel_verify_tpm11(void) 45 { 46 /* verify that it is an Atmel part */ 47 if (tpm_read_index(TPM_ADDR, 4) != 'A' || 48 tpm_read_index(TPM_ADDR, 5) != 'T' || 49 tpm_read_index(TPM_ADDR, 6) != 'M' || 50 tpm_read_index(TPM_ADDR, 7) != 'L') 51 return 1; 52 53 /* query chip for its version number */ 54 if (tpm_read_index(TPM_ADDR, 0x00) != 1 || 55 tpm_read_index(TPM_ADDR, 0x01) != 1) 56 return 1; 57 58 /* This is an atmel supported part */ 59 return 0; 60 } 61 62 /* Determine where to talk to device */ 63 static void __iomem *atmel_get_base_addr(unsigned long *base, int *region_size) 64 { 65 int lo, hi; 66 67 if (atmel_verify_tpm11() != 0) 68 return NULL; 69 70 lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO); 71 hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI); 72 73 *base = (hi << 8) | lo; 74 *region_size = 2; 75 76 return ioport_map(*base, *region_size); 77 } 78 79 /* write status bits */ 80 enum tpm_atmel_write_status { 81 ATML_STATUS_ABORT = 0x01, 82 ATML_STATUS_LASTBYTE = 0x04 83 }; 84 /* read status bits */ 85 enum tpm_atmel_read_status { 86 ATML_STATUS_BUSY = 0x01, 87 ATML_STATUS_DATA_AVAIL = 0x02, 88 ATML_STATUS_REWRITE = 0x04, 89 ATML_STATUS_READY = 0x08 90 }; 91 92 static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) 93 { 94 struct tpm_atmel_priv *priv = dev_get_drvdata(&chip->dev); 95 u8 status, *hdr = buf; 96 u32 size; 97 int i; 98 __be32 *native_size; 99 100 /* start reading header */ 101 if (count < 6) 102 return -EIO; 103 104 for (i = 0; i < 6; i++) { 105 status = ioread8(priv->iobase + 1); 106 if ((status & ATML_STATUS_DATA_AVAIL) == 0) { 107 dev_err(&chip->dev, "error reading header\n"); 108 return -EIO; 109 } 110 *buf++ = ioread8(priv->iobase); 111 } 112 113 /* size of the data received */ 114 native_size = (__force __be32 *) (hdr + 2); 115 size = be32_to_cpu(*native_size); 116 117 if (count < size) { 118 dev_err(&chip->dev, 119 "Recv size(%d) less than available space\n", size); 120 for (; i < size; i++) { /* clear the waiting data anyway */ 121 status = ioread8(priv->iobase + 1); 122 if ((status & ATML_STATUS_DATA_AVAIL) == 0) { 123 dev_err(&chip->dev, "error reading data\n"); 124 return -EIO; 125 } 126 } 127 return -EIO; 128 } 129 130 /* read all the data available */ 131 for (; i < size; i++) { 132 status = ioread8(priv->iobase + 1); 133 if ((status & ATML_STATUS_DATA_AVAIL) == 0) { 134 dev_err(&chip->dev, "error reading data\n"); 135 return -EIO; 136 } 137 *buf++ = ioread8(priv->iobase); 138 } 139 140 /* make sure data available is gone */ 141 status = ioread8(priv->iobase + 1); 142 143 if (status & ATML_STATUS_DATA_AVAIL) { 144 dev_err(&chip->dev, "data available is stuck\n"); 145 return -EIO; 146 } 147 148 return size; 149 } 150 151 static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count) 152 { 153 struct tpm_atmel_priv *priv = dev_get_drvdata(&chip->dev); 154 int i; 155 156 dev_dbg(&chip->dev, "tpm_atml_send:\n"); 157 for (i = 0; i < count; i++) { 158 dev_dbg(&chip->dev, "%d 0x%x(%d)\n", i, buf[i], buf[i]); 159 iowrite8(buf[i], priv->iobase); 160 } 161 162 return 0; 163 } 164 165 static void tpm_atml_cancel(struct tpm_chip *chip) 166 { 167 struct tpm_atmel_priv *priv = dev_get_drvdata(&chip->dev); 168 169 iowrite8(ATML_STATUS_ABORT, priv->iobase + 1); 170 } 171 172 static u8 tpm_atml_status(struct tpm_chip *chip) 173 { 174 struct tpm_atmel_priv *priv = dev_get_drvdata(&chip->dev); 175 176 return ioread8(priv->iobase + 1); 177 } 178 179 static bool tpm_atml_req_canceled(struct tpm_chip *chip, u8 status) 180 { 181 return (status == ATML_STATUS_READY); 182 } 183 184 static const struct tpm_class_ops tpm_atmel = { 185 .recv = tpm_atml_recv, 186 .send = tpm_atml_send, 187 .cancel = tpm_atml_cancel, 188 .status = tpm_atml_status, 189 .req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL, 190 .req_complete_val = ATML_STATUS_DATA_AVAIL, 191 .req_canceled = tpm_atml_req_canceled, 192 }; 193 194 static struct platform_device *pdev; 195 196 static void atml_plat_remove(void) 197 { 198 struct tpm_chip *chip = dev_get_drvdata(&pdev->dev); 199 struct tpm_atmel_priv *priv = dev_get_drvdata(&chip->dev); 200 201 tpm_chip_unregister(chip); 202 if (priv->have_region) 203 atmel_release_region(priv->base, priv->region_size); 204 platform_device_unregister(pdev); 205 } 206 207 static SIMPLE_DEV_PM_OPS(tpm_atml_pm, tpm_pm_suspend, tpm_pm_resume); 208 209 static struct platform_driver atml_drv = { 210 .driver = { 211 .name = "tpm_atmel", 212 .pm = &tpm_atml_pm, 213 }, 214 }; 215 216 static int __init init_atmel(void) 217 { 218 int rc = 0; 219 void __iomem *iobase = NULL; 220 int have_region, region_size; 221 unsigned long base; 222 struct tpm_chip *chip; 223 struct tpm_atmel_priv *priv; 224 225 rc = platform_driver_register(&atml_drv); 226 if (rc) 227 return rc; 228 229 if ((iobase = atmel_get_base_addr(&base, ®ion_size)) == NULL) { 230 rc = -ENODEV; 231 goto err_unreg_drv; 232 } 233 234 have_region = 235 (atmel_request_region 236 (base, region_size, "tpm_atmel0") == NULL) ? 0 : 1; 237 238 pdev = platform_device_register_simple("tpm_atmel", -1, NULL, 0); 239 if (IS_ERR(pdev)) { 240 rc = PTR_ERR(pdev); 241 goto err_rel_reg; 242 } 243 244 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 245 if (!priv) { 246 rc = -ENOMEM; 247 goto err_unreg_dev; 248 } 249 250 priv->iobase = iobase; 251 priv->base = base; 252 priv->have_region = have_region; 253 priv->region_size = region_size; 254 255 chip = tpmm_chip_alloc(&pdev->dev, &tpm_atmel); 256 if (IS_ERR(chip)) { 257 rc = PTR_ERR(chip); 258 goto err_unreg_dev; 259 } 260 261 dev_set_drvdata(&chip->dev, priv); 262 263 rc = tpm_chip_register(chip); 264 if (rc) 265 goto err_unreg_dev; 266 267 return 0; 268 269 err_unreg_dev: 270 platform_device_unregister(pdev); 271 err_rel_reg: 272 if (have_region) 273 atmel_release_region(base, 274 region_size); 275 err_unreg_drv: 276 platform_driver_unregister(&atml_drv); 277 return rc; 278 } 279 280 static void __exit cleanup_atmel(void) 281 { 282 platform_driver_unregister(&atml_drv); 283 atml_plat_remove(); 284 } 285 286 module_init(init_atmel); 287 module_exit(cleanup_atmel); 288 289 MODULE_AUTHOR("Leendert van Doorn <leendert@watson.ibm.com>"); 290 MODULE_DESCRIPTION("TPM Driver"); 291 MODULE_VERSION("2.0"); 292 MODULE_LICENSE("GPL"); 293