linux/drivers/char/tpm/tpm_atmel.c
<<
>>
Prefs
   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#include "tpm_atmel.h"
  19
  20/* write status bits */
  21enum tpm_atmel_write_status {
  22        ATML_STATUS_ABORT = 0x01,
  23        ATML_STATUS_LASTBYTE = 0x04
  24};
  25/* read status bits */
  26enum tpm_atmel_read_status {
  27        ATML_STATUS_BUSY = 0x01,
  28        ATML_STATUS_DATA_AVAIL = 0x02,
  29        ATML_STATUS_REWRITE = 0x04,
  30        ATML_STATUS_READY = 0x08
  31};
  32
  33static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
  34{
  35        struct tpm_atmel_priv *priv = dev_get_drvdata(&chip->dev);
  36        u8 status, *hdr = buf;
  37        u32 size;
  38        int i;
  39        __be32 *native_size;
  40
  41        /* start reading header */
  42        if (count < 6)
  43                return -EIO;
  44
  45        for (i = 0; i < 6; i++) {
  46                status = ioread8(priv->iobase + 1);
  47                if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
  48                        dev_err(&chip->dev, "error reading header\n");
  49                        return -EIO;
  50                }
  51                *buf++ = ioread8(priv->iobase);
  52        }
  53
  54        /* size of the data received */
  55        native_size = (__force __be32 *) (hdr + 2);
  56        size = be32_to_cpu(*native_size);
  57
  58        if (count < size) {
  59                dev_err(&chip->dev,
  60                        "Recv size(%d) less than available space\n", size);
  61                for (; i < size; i++) { /* clear the waiting data anyway */
  62                        status = ioread8(priv->iobase + 1);
  63                        if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
  64                                dev_err(&chip->dev, "error reading data\n");
  65                                return -EIO;
  66                        }
  67                }
  68                return -EIO;
  69        }
  70
  71        /* read all the data available */
  72        for (; i < size; i++) {
  73                status = ioread8(priv->iobase + 1);
  74                if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
  75                        dev_err(&chip->dev, "error reading data\n");
  76                        return -EIO;
  77                }
  78                *buf++ = ioread8(priv->iobase);
  79        }
  80
  81        /* make sure data available is gone */
  82        status = ioread8(priv->iobase + 1);
  83
  84        if (status & ATML_STATUS_DATA_AVAIL) {
  85                dev_err(&chip->dev, "data available is stuck\n");
  86                return -EIO;
  87        }
  88
  89        return size;
  90}
  91
  92static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count)
  93{
  94        struct tpm_atmel_priv *priv = dev_get_drvdata(&chip->dev);
  95        int i;
  96
  97        dev_dbg(&chip->dev, "tpm_atml_send:\n");
  98        for (i = 0; i < count; i++) {
  99                dev_dbg(&chip->dev, "%d 0x%x(%d)\n",  i, buf[i], buf[i]);
 100                iowrite8(buf[i], priv->iobase);
 101        }
 102
 103        return 0;
 104}
 105
 106static void tpm_atml_cancel(struct tpm_chip *chip)
 107{
 108        struct tpm_atmel_priv *priv = dev_get_drvdata(&chip->dev);
 109
 110        iowrite8(ATML_STATUS_ABORT, priv->iobase + 1);
 111}
 112
 113static u8 tpm_atml_status(struct tpm_chip *chip)
 114{
 115        struct tpm_atmel_priv *priv = dev_get_drvdata(&chip->dev);
 116
 117        return ioread8(priv->iobase + 1);
 118}
 119
 120static bool tpm_atml_req_canceled(struct tpm_chip *chip, u8 status)
 121{
 122        return (status == ATML_STATUS_READY);
 123}
 124
 125static const struct tpm_class_ops tpm_atmel = {
 126        .recv = tpm_atml_recv,
 127        .send = tpm_atml_send,
 128        .cancel = tpm_atml_cancel,
 129        .status = tpm_atml_status,
 130        .req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL,
 131        .req_complete_val = ATML_STATUS_DATA_AVAIL,
 132        .req_canceled = tpm_atml_req_canceled,
 133};
 134
 135static struct platform_device *pdev;
 136
 137static void atml_plat_remove(void)
 138{
 139        struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
 140        struct tpm_atmel_priv *priv = dev_get_drvdata(&chip->dev);
 141
 142        tpm_chip_unregister(chip);
 143        if (priv->have_region)
 144                atmel_release_region(priv->base, priv->region_size);
 145        atmel_put_base_addr(priv->iobase);
 146        platform_device_unregister(pdev);
 147}
 148
 149static SIMPLE_DEV_PM_OPS(tpm_atml_pm, tpm_pm_suspend, tpm_pm_resume);
 150
 151static struct platform_driver atml_drv = {
 152        .driver = {
 153                .name = "tpm_atmel",
 154                .pm             = &tpm_atml_pm,
 155        },
 156};
 157
 158static int __init init_atmel(void)
 159{
 160        int rc = 0;
 161        void __iomem *iobase = NULL;
 162        int have_region, region_size;
 163        unsigned long base;
 164        struct  tpm_chip *chip;
 165        struct tpm_atmel_priv *priv;
 166
 167        rc = platform_driver_register(&atml_drv);
 168        if (rc)
 169                return rc;
 170
 171        if ((iobase = atmel_get_base_addr(&base, &region_size)) == NULL) {
 172                rc = -ENODEV;
 173                goto err_unreg_drv;
 174        }
 175
 176        have_region =
 177            (atmel_request_region
 178             (base, region_size, "tpm_atmel0") == NULL) ? 0 : 1;
 179
 180        pdev = platform_device_register_simple("tpm_atmel", -1, NULL, 0);
 181        if (IS_ERR(pdev)) {
 182                rc = PTR_ERR(pdev);
 183                goto err_rel_reg;
 184        }
 185
 186        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 187        if (!priv) {
 188                rc = -ENOMEM;
 189                goto err_unreg_dev;
 190        }
 191
 192        priv->iobase = iobase;
 193        priv->base = base;
 194        priv->have_region = have_region;
 195        priv->region_size = region_size;
 196
 197        chip = tpmm_chip_alloc(&pdev->dev, &tpm_atmel);
 198        if (IS_ERR(chip)) {
 199                rc = PTR_ERR(chip);
 200                goto err_unreg_dev;
 201        }
 202
 203        dev_set_drvdata(&chip->dev, priv);
 204
 205        rc = tpm_chip_register(chip);
 206        if (rc)
 207                goto err_unreg_dev;
 208
 209        return 0;
 210
 211err_unreg_dev:
 212        platform_device_unregister(pdev);
 213err_rel_reg:
 214        atmel_put_base_addr(iobase);
 215        if (have_region)
 216                atmel_release_region(base,
 217                                     region_size);
 218err_unreg_drv:
 219        platform_driver_unregister(&atml_drv);
 220        return rc;
 221}
 222
 223static void __exit cleanup_atmel(void)
 224{
 225        platform_driver_unregister(&atml_drv);
 226        atml_plat_remove();
 227}
 228
 229module_init(init_atmel);
 230module_exit(cleanup_atmel);
 231
 232MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
 233MODULE_DESCRIPTION("TPM Driver");
 234MODULE_VERSION("2.0");
 235MODULE_LICENSE("GPL");
 236