linux/drivers/char/tpm/tpm_tis.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2005, 2006 IBM Corporation
   4 * Copyright (C) 2014, 2015 Intel Corporation
   5 *
   6 * Authors:
   7 * Leendert van Doorn <leendert@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 device driver implements the TPM interface as defined in
  16 * the TCG TPM Interface Spec version 1.2, revision 1.0.
  17 */
  18#include <linux/init.h>
  19#include <linux/module.h>
  20#include <linux/moduleparam.h>
  21#include <linux/pnp.h>
  22#include <linux/slab.h>
  23#include <linux/interrupt.h>
  24#include <linux/wait.h>
  25#include <linux/acpi.h>
  26#include <linux/freezer.h>
  27#include <linux/of.h>
  28#include <linux/of_device.h>
  29#include <linux/kernel.h>
  30#include <linux/dmi.h>
  31#include "tpm.h"
  32#include "tpm_tis_core.h"
  33
  34struct tpm_info {
  35        struct resource res;
  36        /* irq > 0 means: use irq $irq;
  37         * irq = 0 means: autoprobe for an irq;
  38         * irq = -1 means: no irq support
  39         */
  40        int irq;
  41};
  42
  43struct tpm_tis_tcg_phy {
  44        struct tpm_tis_data priv;
  45        void __iomem *iobase;
  46};
  47
  48static inline struct tpm_tis_tcg_phy *to_tpm_tis_tcg_phy(struct tpm_tis_data *data)
  49{
  50        return container_of(data, struct tpm_tis_tcg_phy, priv);
  51}
  52
  53static int interrupts = -1;
  54module_param(interrupts, int, 0444);
  55MODULE_PARM_DESC(interrupts, "Enable interrupts");
  56
  57static bool itpm;
  58module_param(itpm, bool, 0444);
  59MODULE_PARM_DESC(itpm, "Force iTPM workarounds (found on some Lenovo laptops)");
  60
  61static bool force;
  62#ifdef CONFIG_X86
  63module_param(force, bool, 0444);
  64MODULE_PARM_DESC(force, "Force device probe rather than using ACPI entry");
  65#endif
  66
  67static int tpm_tis_disable_irq(const struct dmi_system_id *d)
  68{
  69        if (interrupts == -1) {
  70                pr_notice("tpm_tis: %s detected: disabling interrupts.\n", d->ident);
  71                interrupts = 0;
  72        }
  73
  74        return 0;
  75}
  76
  77static const struct dmi_system_id tpm_tis_dmi_table[] = {
  78        {
  79                .callback = tpm_tis_disable_irq,
  80                .ident = "ThinkPad T490s",
  81                .matches = {
  82                        DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
  83                        DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T490s"),
  84                },
  85        },
  86        {}
  87};
  88
  89#if defined(CONFIG_PNP) && defined(CONFIG_ACPI)
  90static int has_hid(struct acpi_device *dev, const char *hid)
  91{
  92        struct acpi_hardware_id *id;
  93
  94        list_for_each_entry(id, &dev->pnp.ids, list)
  95                if (!strcmp(hid, id->id))
  96                        return 1;
  97
  98        return 0;
  99}
 100
 101static inline int is_itpm(struct acpi_device *dev)
 102{
 103        if (!dev)
 104                return 0;
 105        return has_hid(dev, "INTC0102");
 106}
 107#else
 108static inline int is_itpm(struct acpi_device *dev)
 109{
 110        return 0;
 111}
 112#endif
 113
 114#if defined(CONFIG_ACPI)
 115#define DEVICE_IS_TPM2 1
 116
 117static const struct acpi_device_id tpm_acpi_tbl[] = {
 118        {"MSFT0101", DEVICE_IS_TPM2},
 119        {},
 120};
 121MODULE_DEVICE_TABLE(acpi, tpm_acpi_tbl);
 122
 123static int check_acpi_tpm2(struct device *dev)
 124{
 125        const struct acpi_device_id *aid = acpi_match_device(tpm_acpi_tbl, dev);
 126        struct acpi_table_tpm2 *tbl;
 127        acpi_status st;
 128
 129        if (!aid || aid->driver_data != DEVICE_IS_TPM2)
 130                return 0;
 131
 132        /* If the ACPI TPM2 signature is matched then a global ACPI_SIG_TPM2
 133         * table is mandatory
 134         */
 135        st =
 136            acpi_get_table(ACPI_SIG_TPM2, 1, (struct acpi_table_header **)&tbl);
 137        if (ACPI_FAILURE(st) || tbl->header.length < sizeof(*tbl)) {
 138                dev_err(dev, FW_BUG "failed to get TPM2 ACPI table\n");
 139                return -EINVAL;
 140        }
 141
 142        /* The tpm2_crb driver handles this device */
 143        if (tbl->start_method != ACPI_TPM2_MEMORY_MAPPED)
 144                return -ENODEV;
 145
 146        return 0;
 147}
 148#else
 149static int check_acpi_tpm2(struct device *dev)
 150{
 151        return 0;
 152}
 153#endif
 154
 155static int tpm_tcg_read_bytes(struct tpm_tis_data *data, u32 addr, u16 len,
 156                              u8 *result)
 157{
 158        struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
 159
 160        while (len--)
 161                *result++ = ioread8(phy->iobase + addr);
 162
 163        return 0;
 164}
 165
 166static int tpm_tcg_write_bytes(struct tpm_tis_data *data, u32 addr, u16 len,
 167                               const u8 *value)
 168{
 169        struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
 170
 171        while (len--)
 172                iowrite8(*value++, phy->iobase + addr);
 173
 174        return 0;
 175}
 176
 177static int tpm_tcg_read16(struct tpm_tis_data *data, u32 addr, u16 *result)
 178{
 179        struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
 180
 181        *result = ioread16(phy->iobase + addr);
 182
 183        return 0;
 184}
 185
 186static int tpm_tcg_read32(struct tpm_tis_data *data, u32 addr, u32 *result)
 187{
 188        struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
 189
 190        *result = ioread32(phy->iobase + addr);
 191
 192        return 0;
 193}
 194
 195static int tpm_tcg_write32(struct tpm_tis_data *data, u32 addr, u32 value)
 196{
 197        struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
 198
 199        iowrite32(value, phy->iobase + addr);
 200
 201        return 0;
 202}
 203
 204static const struct tpm_tis_phy_ops tpm_tcg = {
 205        .read_bytes = tpm_tcg_read_bytes,
 206        .write_bytes = tpm_tcg_write_bytes,
 207        .read16 = tpm_tcg_read16,
 208        .read32 = tpm_tcg_read32,
 209        .write32 = tpm_tcg_write32,
 210};
 211
 212static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info)
 213{
 214        struct tpm_tis_tcg_phy *phy;
 215        int irq = -1;
 216        int rc;
 217
 218        dmi_check_system(tpm_tis_dmi_table);
 219
 220        rc = check_acpi_tpm2(dev);
 221        if (rc)
 222                return rc;
 223
 224        phy = devm_kzalloc(dev, sizeof(struct tpm_tis_tcg_phy), GFP_KERNEL);
 225        if (phy == NULL)
 226                return -ENOMEM;
 227
 228        phy->iobase = devm_ioremap_resource(dev, &tpm_info->res);
 229        if (IS_ERR(phy->iobase))
 230                return PTR_ERR(phy->iobase);
 231
 232        if (interrupts)
 233                irq = tpm_info->irq;
 234
 235        if (itpm || is_itpm(ACPI_COMPANION(dev)))
 236                phy->priv.flags |= TPM_TIS_ITPM_WORKAROUND;
 237
 238        return tpm_tis_core_init(dev, &phy->priv, irq, &tpm_tcg,
 239                                 ACPI_HANDLE(dev));
 240}
 241
 242static SIMPLE_DEV_PM_OPS(tpm_tis_pm, tpm_pm_suspend, tpm_tis_resume);
 243
 244static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
 245                            const struct pnp_device_id *pnp_id)
 246{
 247        struct tpm_info tpm_info = {};
 248        struct resource *res;
 249
 250        res = pnp_get_resource(pnp_dev, IORESOURCE_MEM, 0);
 251        if (!res)
 252                return -ENODEV;
 253        tpm_info.res = *res;
 254
 255        if (pnp_irq_valid(pnp_dev, 0))
 256                tpm_info.irq = pnp_irq(pnp_dev, 0);
 257        else
 258                tpm_info.irq = -1;
 259
 260        return tpm_tis_init(&pnp_dev->dev, &tpm_info);
 261}
 262
 263static struct pnp_device_id tpm_pnp_tbl[] = {
 264        {"PNP0C31", 0},         /* TPM */
 265        {"ATM1200", 0},         /* Atmel */
 266        {"IFX0102", 0},         /* Infineon */
 267        {"BCM0101", 0},         /* Broadcom */
 268        {"BCM0102", 0},         /* Broadcom */
 269        {"NSC1200", 0},         /* National */
 270        {"ICO0102", 0},         /* Intel */
 271        /* Add new here */
 272        {"", 0},                /* User Specified */
 273        {"", 0}                 /* Terminator */
 274};
 275MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl);
 276
 277static void tpm_tis_pnp_remove(struct pnp_dev *dev)
 278{
 279        struct tpm_chip *chip = pnp_get_drvdata(dev);
 280
 281        tpm_chip_unregister(chip);
 282        tpm_tis_remove(chip);
 283}
 284
 285static struct pnp_driver tis_pnp_driver = {
 286        .name = "tpm_tis",
 287        .id_table = tpm_pnp_tbl,
 288        .probe = tpm_tis_pnp_init,
 289        .remove = tpm_tis_pnp_remove,
 290        .driver = {
 291                .pm = &tpm_tis_pm,
 292        },
 293};
 294
 295#define TIS_HID_USR_IDX (ARRAY_SIZE(tpm_pnp_tbl) - 2)
 296module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
 297                    sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444);
 298MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
 299
 300static struct platform_device *force_pdev;
 301
 302static int tpm_tis_plat_probe(struct platform_device *pdev)
 303{
 304        struct tpm_info tpm_info = {};
 305        struct resource *res;
 306
 307        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 308        if (res == NULL) {
 309                dev_err(&pdev->dev, "no memory resource defined\n");
 310                return -ENODEV;
 311        }
 312        tpm_info.res = *res;
 313
 314        tpm_info.irq = platform_get_irq(pdev, 0);
 315        if (tpm_info.irq <= 0) {
 316                if (pdev != force_pdev)
 317                        tpm_info.irq = -1;
 318                else
 319                        /* When forcing auto probe the IRQ */
 320                        tpm_info.irq = 0;
 321        }
 322
 323        return tpm_tis_init(&pdev->dev, &tpm_info);
 324}
 325
 326static int tpm_tis_plat_remove(struct platform_device *pdev)
 327{
 328        struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
 329
 330        tpm_chip_unregister(chip);
 331        tpm_tis_remove(chip);
 332
 333        return 0;
 334}
 335
 336#ifdef CONFIG_OF
 337static const struct of_device_id tis_of_platform_match[] = {
 338        {.compatible = "tcg,tpm-tis-mmio"},
 339        {},
 340};
 341MODULE_DEVICE_TABLE(of, tis_of_platform_match);
 342#endif
 343
 344static struct platform_driver tis_drv = {
 345        .probe = tpm_tis_plat_probe,
 346        .remove = tpm_tis_plat_remove,
 347        .driver = {
 348                .name           = "tpm_tis",
 349                .pm             = &tpm_tis_pm,
 350                .of_match_table = of_match_ptr(tis_of_platform_match),
 351                .acpi_match_table = ACPI_PTR(tpm_acpi_tbl),
 352        },
 353};
 354
 355static int tpm_tis_force_device(void)
 356{
 357        struct platform_device *pdev;
 358        static const struct resource x86_resources[] = {
 359                DEFINE_RES_MEM(0xFED40000, TIS_MEM_LEN)
 360        };
 361
 362        if (!force)
 363                return 0;
 364
 365        /* The driver core will match the name tpm_tis of the device to
 366         * the tpm_tis platform driver and complete the setup via
 367         * tpm_tis_plat_probe
 368         */
 369        pdev = platform_device_register_simple("tpm_tis", -1, x86_resources,
 370                                               ARRAY_SIZE(x86_resources));
 371        if (IS_ERR(pdev))
 372                return PTR_ERR(pdev);
 373        force_pdev = pdev;
 374
 375        return 0;
 376}
 377
 378static int __init init_tis(void)
 379{
 380        int rc;
 381
 382        rc = tpm_tis_force_device();
 383        if (rc)
 384                goto err_force;
 385
 386        rc = platform_driver_register(&tis_drv);
 387        if (rc)
 388                goto err_platform;
 389
 390
 391        if (IS_ENABLED(CONFIG_PNP)) {
 392                rc = pnp_register_driver(&tis_pnp_driver);
 393                if (rc)
 394                        goto err_pnp;
 395        }
 396
 397        return 0;
 398
 399err_pnp:
 400        platform_driver_unregister(&tis_drv);
 401err_platform:
 402        if (force_pdev)
 403                platform_device_unregister(force_pdev);
 404err_force:
 405        return rc;
 406}
 407
 408static void __exit cleanup_tis(void)
 409{
 410        pnp_unregister_driver(&tis_pnp_driver);
 411        platform_driver_unregister(&tis_drv);
 412
 413        if (force_pdev)
 414                platform_device_unregister(force_pdev);
 415}
 416
 417module_init(init_tis);
 418module_exit(cleanup_tis);
 419MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
 420MODULE_DESCRIPTION("TPM Driver");
 421MODULE_VERSION("2.0");
 422MODULE_LICENSE("GPL");
 423