static int tpm_tis_i2c_wait_for_stat(struct udevice *dev, u8 mask, unsigned long timeout, int *status) { unsigned long start, stop; /* Check current status */ *status = tpm_tis_i2c_status(dev); if ((*status & mask) == mask) return 0; start = get_timer(0); stop = timeout; do { mdelay(TPM_TIMEOUT_MS); *status = tpm_tis_i2c_status(dev); if ((*status & mask) == mask) return 0; } while (get_timer(start) < stop); return -ETIMEDOUT; }
static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, int *status) { unsigned long stop; /* check current status */ *status = tpm_tis_i2c_status(chip); if ((*status & mask) == mask) return 0; stop = jiffies + timeout; do { /* since we just checked the status, give the TPM some time */ usleep_range(TPM_TIMEOUT_US_LOW, TPM_TIMEOUT_US_HI); *status = tpm_tis_i2c_status(chip); if ((*status & mask) == mask) return 0; } while (time_before(jiffies, stop)); return -ETIME; }
static int tpm_tis_i2c_recv(struct udevice *dev, u8 *buf, size_t count) { struct tpm_chip *chip = dev_get_priv(dev); int size = 0; int status; unsigned int expected; int rc; status = tpm_tis_i2c_status(dev); if (status == TPM_STS_COMMAND_READY) return -EINTR; if ((status & (TPM_STS_DATA_AVAIL | TPM_STS_VALID)) != (TPM_STS_DATA_AVAIL | TPM_STS_VALID)) return -EAGAIN; debug("...got it;\n"); /* Read first 10 bytes, including tag, paramsize, and result */ size = tpm_tis_i2c_recv_data(dev, buf, TPM_HEADER_SIZE); if (size < TPM_HEADER_SIZE) { debug("Unable to read header\n"); return size < 0 ? size : -EIO; } expected = get_unaligned_be32(buf + TPM_RSP_SIZE_BYTE); if ((size_t)expected > count || (size_t)expected < TPM_HEADER_SIZE) { debug("Error size=%x, expected=%x, count=%x\n", size, expected, count); return -ENOSPC; } size += tpm_tis_i2c_recv_data(dev, &buf[TPM_HEADER_SIZE], expected - TPM_HEADER_SIZE); if (size < expected) { debug("Unable to read remainder of result\n"); return -ETIMEDOUT; } rc = tpm_tis_i2c_wait_for_stat(dev, TPM_STS_VALID, chip->timeout_c, &status); if (rc) return rc; if (status & TPM_STS_DATA_AVAIL) { /* Retry? */ debug("Error left over data\n"); return -EIO; } return size; }
static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) { int rc, status; ssize_t burstcnt; size_t count = 0; u8 retries = 0; u8 sts = TPM_STS_GO; if (len > TPM_BUFSIZE) return -E2BIG; /* command is too long for our tpm, sorry */ if (request_locality(chip, 0) < 0) return -EBUSY; status = tpm_tis_i2c_status(chip); if ((status & TPM_STS_COMMAND_READY) == 0) { tpm_tis_i2c_ready(chip); if (wait_for_stat (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b, &status) < 0) { rc = -ETIME; goto out_err; } } while (count < len - 1) { burstcnt = get_burstcount(chip); /* burstcnt < 0 = TPM is busy */ if (burstcnt < 0) return burstcnt; if (burstcnt > (len - 1 - count)) burstcnt = len - 1 - count; rc = iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), &(buf[count]), burstcnt); if (rc == 0) count += burstcnt; else if (rc < 0) retries++; /* avoid endless loop in case of broken HW */ if (retries > MAX_COUNT_LONG) { rc = -EIO; goto out_err; } wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status); if ((status & TPM_STS_DATA_EXPECT) == 0) { rc = -EIO; goto out_err; } } /* write last byte */ iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), &(buf[count]), 1); wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status); if ((status & TPM_STS_DATA_EXPECT) != 0) { rc = -EIO; goto out_err; } /* go and do it */ iic_tpm_write(TPM_STS(chip->vendor.locality), &sts, 1); return len; out_err: tpm_tis_i2c_ready(chip); /* The TPM needs some time to clean up here, * so we sleep rather than keeping the bus busy */ usleep_range(SLEEP_DURATION_RESET_LOW, SLEEP_DURATION_RESET_HI); release_locality(chip, chip->vendor.locality, 0); return rc; }
static int tpm_tis_i2c_send(struct udevice *dev, const u8 *buf, size_t len) { struct tpm_chip *chip = dev_get_priv(dev); int rc, status; size_t burstcnt; size_t count = 0; int retry = 0; u8 sts = TPM_STS_GO; debug("%s: len=%d\n", __func__, len); if (len > TPM_DEV_BUFSIZE) return -E2BIG; /* Command is too long for our tpm, sorry */ if (tpm_tis_i2c_request_locality(dev, 0) < 0) return -EBUSY; status = tpm_tis_i2c_status(dev); if ((status & TPM_STS_COMMAND_READY) == 0) { rc = tpm_tis_i2c_ready(dev); if (rc) return rc; rc = tpm_tis_i2c_wait_for_stat(dev, TPM_STS_COMMAND_READY, chip->timeout_b, &status); if (rc) return rc; } burstcnt = tpm_tis_i2c_get_burstcount(dev); /* burstcount < 0 -> tpm is busy */ if (burstcnt < 0) return burstcnt; while (count < len) { udelay(300); if (burstcnt > len - count) burstcnt = len - count; #ifdef CONFIG_TPM_TIS_I2C_BURST_LIMITATION if (retry && burstcnt > CONFIG_TPM_TIS_I2C_BURST_LIMITATION_LEN) burstcnt = CONFIG_TPM_TIS_I2C_BURST_LIMITATION_LEN; #endif /* CONFIG_TPM_TIS_I2C_BURST_LIMITATION */ rc = tpm_tis_i2c_write(dev, TPM_DATA_FIFO(chip->locality), &(buf[count]), burstcnt); if (rc == 0) count += burstcnt; else { debug("%s: error\n", __func__); if (retry++ > 10) return -EIO; rc = tpm_tis_i2c_wait_for_stat(dev, TPM_STS_VALID, chip->timeout_c, &status); if (rc) return rc; if ((status & TPM_STS_DATA_EXPECT) == 0) return -EIO; } } /* Go and do it */ rc = tpm_tis_i2c_write(dev, TPM_STS(chip->locality), &sts, 1); if (rc < 0) return rc; debug("%s: done, rc=%d\n", __func__, rc); return len; }