^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2004 IBM Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Authors:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Leendert van Doorn <leendert@watson.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Dave Safford <safford@watson.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Reiner Sailer <sailer@watson.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Kylene Hall <kjhall@us.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Maintained by: <tpmdd-devel@lists.sourceforge.net>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Device driver for TCG/TCPA TPM (trusted platform module).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * Specifications at www.trustedcomputinggroup.org
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "tpm.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) /* National definitions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) enum tpm_nsc_addr{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) TPM_NSC_IRQ = 0x07,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) TPM_NSC_BASE0_HI = 0x60,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) TPM_NSC_BASE0_LO = 0x61,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) TPM_NSC_BASE1_HI = 0x62,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) TPM_NSC_BASE1_LO = 0x63
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) enum tpm_nsc_index {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) NSC_LDN_INDEX = 0x07,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) NSC_SID_INDEX = 0x20,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) NSC_LDC_INDEX = 0x30,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) NSC_DIO_INDEX = 0x60,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) NSC_CIO_INDEX = 0x62,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) NSC_IRQ_INDEX = 0x70,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) NSC_ITS_INDEX = 0x71
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) enum tpm_nsc_status_loc {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) NSC_STATUS = 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) NSC_COMMAND = 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) NSC_DATA = 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /* status bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) enum tpm_nsc_status {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) NSC_STATUS_OBF = 0x01, /* output buffer full */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) NSC_STATUS_IBF = 0x02, /* input buffer full */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) NSC_STATUS_F0 = 0x04, /* F0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) NSC_STATUS_A2 = 0x08, /* A2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) NSC_STATUS_RDY = 0x10, /* ready to receive command */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) NSC_STATUS_IBR = 0x20 /* ready to receive data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) /* command bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) enum tpm_nsc_cmd_mode {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) NSC_COMMAND_NORMAL = 0x01, /* normal mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) NSC_COMMAND_EOC = 0x03,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) NSC_COMMAND_CANCEL = 0x22
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) struct tpm_nsc_priv {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) unsigned long base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * Wait for a certain status to appear
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct tpm_nsc_priv *priv = dev_get_drvdata(&chip->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) unsigned long stop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) /* status immediately available check */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) *data = inb(priv->base + NSC_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) if ((*data & mask) == val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) /* wait for status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) stop = jiffies + 10 * HZ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) msleep(TPM_TIMEOUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) *data = inb(priv->base + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) if ((*data & mask) == val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) while (time_before(jiffies, stop));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) static int nsc_wait_for_ready(struct tpm_chip *chip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) struct tpm_nsc_priv *priv = dev_get_drvdata(&chip->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) unsigned long stop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) /* status immediately available check */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) status = inb(priv->base + NSC_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) if (status & NSC_STATUS_OBF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) status = inb(priv->base + NSC_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) if (status & NSC_STATUS_RDY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) /* wait for status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) stop = jiffies + 100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) msleep(TPM_TIMEOUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) status = inb(priv->base + NSC_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (status & NSC_STATUS_OBF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) status = inb(priv->base + NSC_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if (status & NSC_STATUS_RDY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) while (time_before(jiffies, stop));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) dev_info(&chip->dev, "wait for ready failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) struct tpm_nsc_priv *priv = dev_get_drvdata(&chip->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) u8 *buffer = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) u8 data, *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) u32 size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) __be32 *native_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (count < 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) if (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) dev_err(&chip->dev, "F0 timeout\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) data = inb(priv->base + NSC_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) if (data != NSC_COMMAND_NORMAL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) dev_err(&chip->dev, "not in normal mode (0x%x)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) /* read the whole packet */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) for (p = buffer; p < &buffer[count]; p++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (wait_for_stat
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) (chip, NSC_STATUS_OBF, NSC_STATUS_OBF, &data) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) dev_err(&chip->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) "OBF timeout (while reading data)\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if (data & NSC_STATUS_F0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) *p = inb(priv->base + NSC_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) if ((data & NSC_STATUS_F0) == 0 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) dev_err(&chip->dev, "F0 not set\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) data = inb(priv->base + NSC_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) if (data != NSC_COMMAND_EOC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) dev_err(&chip->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) "expected end of command(0x%x)\n", data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) native_size = (__force __be32 *) (buf + 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) size = be32_to_cpu(*native_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) if (count < size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) return size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) struct tpm_nsc_priv *priv = dev_get_drvdata(&chip->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) u8 data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * If we hit the chip with back to back commands it locks up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * and never set IBF. Hitting it with this "hammer" seems to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) * fix it. Not sure why this is needed, we followed the flow
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) * chart in the manual to the letter.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) outb(NSC_COMMAND_CANCEL, priv->base + NSC_COMMAND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (nsc_wait_for_ready(chip) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) dev_err(&chip->dev, "IBF timeout\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) outb(NSC_COMMAND_NORMAL, priv->base + NSC_COMMAND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) if (wait_for_stat(chip, NSC_STATUS_IBR, NSC_STATUS_IBR, &data) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) dev_err(&chip->dev, "IBR timeout\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) for (i = 0; i < count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) dev_err(&chip->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) "IBF timeout (while writing data)\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) outb(buf[i], priv->base + NSC_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) dev_err(&chip->dev, "IBF timeout\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) outb(NSC_COMMAND_EOC, priv->base + NSC_COMMAND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) static void tpm_nsc_cancel(struct tpm_chip *chip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) struct tpm_nsc_priv *priv = dev_get_drvdata(&chip->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) outb(NSC_COMMAND_CANCEL, priv->base + NSC_COMMAND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) static u8 tpm_nsc_status(struct tpm_chip *chip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) struct tpm_nsc_priv *priv = dev_get_drvdata(&chip->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) return inb(priv->base + NSC_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) static bool tpm_nsc_req_canceled(struct tpm_chip *chip, u8 status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) return (status == NSC_STATUS_RDY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) static const struct tpm_class_ops tpm_nsc = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) .recv = tpm_nsc_recv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) .send = tpm_nsc_send,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) .cancel = tpm_nsc_cancel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) .status = tpm_nsc_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) .req_complete_mask = NSC_STATUS_OBF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) .req_complete_val = NSC_STATUS_OBF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) .req_canceled = tpm_nsc_req_canceled,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) static struct platform_device *pdev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) static void tpm_nsc_remove(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) struct tpm_chip *chip = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) struct tpm_nsc_priv *priv = dev_get_drvdata(&chip->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) tpm_chip_unregister(chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) release_region(priv->base, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) static SIMPLE_DEV_PM_OPS(tpm_nsc_pm, tpm_pm_suspend, tpm_pm_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) static struct platform_driver nsc_drv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) .name = "tpm_nsc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) .pm = &tpm_nsc_pm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) static inline int tpm_read_index(int base, int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) outb(index, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) return inb(base+1) & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) static inline void tpm_write_index(int base, int index, int value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) outb(index, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) outb(value & 0xFF, base+1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) static int __init init_nsc(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) int rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) int lo, hi, err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) int nscAddrBase = TPM_ADDR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) struct tpm_chip *chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) unsigned long base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) struct tpm_nsc_priv *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) /* verify that it is a National part (SID) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) if (tpm_read_index(TPM_ADDR, NSC_SID_INDEX) != 0xEF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) nscAddrBase = (tpm_read_index(TPM_SUPERIO_ADDR, 0x2C)<<8)|
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) (tpm_read_index(TPM_SUPERIO_ADDR, 0x2B)&0xFE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) if (tpm_read_index(nscAddrBase, NSC_SID_INDEX) != 0xF6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) err = platform_driver_register(&nsc_drv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) hi = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_HI);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) lo = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_LO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) base = (hi<<8) | lo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) /* enable the DPM module */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) tpm_write_index(nscAddrBase, NSC_LDC_INDEX, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) pdev = platform_device_alloc("tpm_nscl0", -1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) if (!pdev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) rc = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) goto err_unreg_drv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) pdev->num_resources = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) pdev->dev.driver = &nsc_drv.driver;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) pdev->dev.release = tpm_nsc_remove;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) if ((rc = platform_device_add(pdev)) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) goto err_put_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) if (!priv) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) rc = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) goto err_del_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) priv->base = base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) if (request_region(base, 2, "tpm_nsc0") == NULL ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) rc = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) goto err_del_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) chip = tpmm_chip_alloc(&pdev->dev, &tpm_nsc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) if (IS_ERR(chip)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) rc = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) goto err_rel_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) dev_set_drvdata(&chip->dev, priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) rc = tpm_chip_register(chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) goto err_rel_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) dev_dbg(&pdev->dev, "NSC TPM detected\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) dev_dbg(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) "NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) tpm_read_index(nscAddrBase,0x07), tpm_read_index(nscAddrBase,0x20),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) tpm_read_index(nscAddrBase,0x27));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) dev_dbg(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) "NSC SIOCF1 0x%x SIOCF5 0x%x SIOCF6 0x%x SIOCF8 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) tpm_read_index(nscAddrBase,0x21), tpm_read_index(nscAddrBase,0x25),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) tpm_read_index(nscAddrBase,0x26), tpm_read_index(nscAddrBase,0x28));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) dev_dbg(&pdev->dev, "NSC IO Base0 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) (tpm_read_index(nscAddrBase,0x60) << 8) | tpm_read_index(nscAddrBase,0x61));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) dev_dbg(&pdev->dev, "NSC IO Base1 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) (tpm_read_index(nscAddrBase,0x62) << 8) | tpm_read_index(nscAddrBase,0x63));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) dev_dbg(&pdev->dev, "NSC Interrupt number and wakeup 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) tpm_read_index(nscAddrBase,0x70));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) dev_dbg(&pdev->dev, "NSC IRQ type select 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) tpm_read_index(nscAddrBase,0x71));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) dev_dbg(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) "NSC DMA channel select0 0x%x, select1 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) tpm_read_index(nscAddrBase,0x74), tpm_read_index(nscAddrBase,0x75));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) dev_dbg(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) "NSC Config "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) tpm_read_index(nscAddrBase,0xF0), tpm_read_index(nscAddrBase,0xF1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) tpm_read_index(nscAddrBase,0xF2), tpm_read_index(nscAddrBase,0xF3),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) tpm_read_index(nscAddrBase,0xF4), tpm_read_index(nscAddrBase,0xF5),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) tpm_read_index(nscAddrBase,0xF6), tpm_read_index(nscAddrBase,0xF7),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) tpm_read_index(nscAddrBase,0xF8), tpm_read_index(nscAddrBase,0xF9));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) dev_info(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) "NSC TPM revision %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) tpm_read_index(nscAddrBase, 0x27) & 0x1F);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) err_rel_reg:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) release_region(base, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) err_del_dev:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) platform_device_del(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) err_put_dev:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) platform_device_put(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) err_unreg_drv:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) platform_driver_unregister(&nsc_drv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) static void __exit cleanup_nsc(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) if (pdev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) tpm_nsc_remove(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) platform_device_unregister(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) platform_driver_unregister(&nsc_drv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) module_init(init_nsc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) module_exit(cleanup_nsc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) MODULE_DESCRIPTION("TPM Driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) MODULE_VERSION("2.0");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) MODULE_LICENSE("GPL");