/* cr50 uses bytes 3:2 of status register for burst count and * all 4 bytes must be read */ static int cr50_i2c_wait_burststs(struct tpm_chip *chip, uint8_t mask, size_t *burst, int *status) { uint8_t buf[4]; struct stopwatch sw; stopwatch_init_msecs_expire(&sw, CR50_TIMEOUT_LONG_MS); while (!stopwatch_expired(&sw)) { if (cr50_i2c_read(chip, TPM_STS(chip->vendor.locality), buf, sizeof(buf)) != 0) { mdelay(CR50_TIMEOUT_SHORT_MS); continue; } *status = buf[0]; *burst = read_le16(&buf[1]); /* Check if mask matches and burst is valid */ if ((*status & mask) == mask && *burst > 0 && *burst <= CR50_MAX_BUFSIZE) return 0; mdelay(CR50_TIMEOUT_SHORT_MS); } printk(BIOS_ERR, "%s: Timeout reading burst and status\n", __func__); return -1; }
static ssize_t tpm_tis_i2c_get_burstcount(struct udevice *dev) { struct tpm_chip *chip = dev_get_priv(dev); unsigned long start, stop; ssize_t burstcnt; u8 addr, buf[3]; /* Wait for burstcount */ /* XXX: Which timeout value? Spec has 2 answers (c & d) */ start = get_timer(0); stop = chip->timeout_d; do { /* Note: STS is little endian */ addr = TPM_STS(chip->locality) + 1; if (tpm_tis_i2c_read(dev, addr, buf, 3) < 0) burstcnt = 0; else burstcnt = (buf[2] << 16) + (buf[1] << 8) + buf[0]; if (burstcnt) return burstcnt; mdelay(TPM_TIMEOUT_MS); } while (get_timer(start) < stop); return -EBUSY; }
static int get_burstcount(struct tpm_chip* tpm) { s_time_t stop; int burstcnt; stop = NOW() + tpm->timeout_d; do { burstcnt = ioread8((TPM_STS(tpm, tpm->locality) + 1)); burstcnt += ioread8(TPM_STS(tpm, tpm->locality) + 2) << 8; if (burstcnt) { return burstcnt; } msleep(TPM_TIMEOUT); } while(NOW() < stop); return -EBUSY; }
static u8 tpm_tis_i2c_status(struct tpm_chip *chip) { /* NOTE: since I2C read may fail, return 0 in this case --> time-out */ u8 buf; if (iic_tpm_read(TPM_STS(chip->vendor.locality), &buf, 1) < 0) return 0; else return buf; }
/* cr50 requires all 4 bytes of status register to be read */ static uint8_t cr50_i2c_tis_status(struct tpm_chip *chip) { uint8_t buf[4]; if (cr50_i2c_read(chip, TPM_STS(chip->vendor.locality), buf, sizeof(buf)) < 0) { printk(BIOS_ERR, "%s: Failed to read status\n", __func__); return 0; } return buf[0]; }
static u8 tpm_tis_i2c_status(struct udevice *dev) { struct tpm_chip *chip = dev_get_priv(dev); /* NOTE: Since i2c read may fail, return 0 in this case --> time-out */ u8 buf; if (tpm_tis_i2c_read(dev, TPM_STS(chip->locality), &buf, 1) < 0) return 0; else return buf; }
static int tpm_tis_i2c_ready(struct udevice *dev) { struct tpm_chip *chip = dev_get_priv(dev); int rc; /* This causes the current command to be aborted */ u8 buf = TPM_STS_COMMAND_READY; debug("%s\n", __func__); rc = tpm_tis_i2c_write_long(dev, TPM_STS(chip->locality), &buf, 1); if (rc) debug("%s: rc=%d\n", __func__, rc); return rc; }
static ssize_t get_burstcount(struct tpm_chip *chip) { unsigned long stop; ssize_t burstcnt; u8 buf[3]; /* wait for burstcount */ /* which timeout value, spec has 2 answers (c & d) */ stop = jiffies + chip->vendor.timeout_d; do { /* Note: STS is little endian */ if (iic_tpm_read(TPM_STS(chip->vendor.locality)+1, buf, 3) < 0) burstcnt = 0; else burstcnt = (buf[2] << 16) + (buf[1] << 8) + buf[0]; if (burstcnt) return burstcnt; usleep_range(TPM_TIMEOUT_US_LOW, TPM_TIMEOUT_US_HI); } while (time_before(jiffies, stop)); return -EBUSY; }
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 void tpm_tis_i2c_ready(struct tpm_chip *chip) { /* this causes the current command to be aborted */ u8 buf = TPM_STS_COMMAND_READY; iic_tpm_write_long(TPM_STS(chip->vendor.locality), &buf, 1); }
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; }
int tpm_tis_send(struct tpm_chip* tpm, uint8_t* buf, size_t len) { int rc; int status, burstcnt = 0; int count = 0; uint32_t ordinal; if(tpm_tis_request_locality(tpm, tpm->locality) < 0) { return -EBUSY; } status = tpm_tis_status(tpm); if((status & TPM_STS_COMMAND_READY) == 0) { tpm_tis_ready(tpm); if(wait_for_stat(tpm, TPM_STS_COMMAND_READY, tpm->timeout_b, &tpm->int_queue) < 0) { rc = -ETIME; goto out_err; } } while(count < len - 1) { burstcnt = get_burstcount(tpm); for(;burstcnt > 0 && count < len -1; --burstcnt) { iowrite8(TPM_DATA_FIFO(tpm, tpm->locality), buf[count++]); } wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->int_queue); status = tpm_tis_status(tpm); if((status & TPM_STS_DATA_EXPECT) == 0) { rc = -EIO; goto out_err; } } /*Write last byte*/ iowrite8(TPM_DATA_FIFO(tpm, tpm->locality), buf[count]); wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->read_queue); status = tpm_tis_status(tpm); if((status & TPM_STS_DATA_EXPECT) != 0) { rc = -EIO; goto out_err; } /*go and do it*/ iowrite8(TPM_STS(tpm, tpm->locality), TPM_STS_GO); if(tpm->irq) { /*Wait for interrupt */ ordinal = be32_to_cpu(*(buf + 6)); if(wait_for_stat(tpm, TPM_STS_DATA_AVAIL | TPM_STS_VALID, tpm_calc_ordinal_duration(tpm, ordinal), &tpm->read_queue) < 0) { rc = -ETIME; goto out_err; } } #ifdef HAVE_LIBC if(tpm->fd >= 0) { files[tpm->fd].read = 0; files[tpm->fd].tpm_tis.respgot = 0; files[tpm->fd].tpm_tis.offset = 0; } #endif return len; out_err: tpm_tis_ready(tpm); release_locality(tpm, tpm->locality, 0); return rc; }
/* This causes the current command to be aborted */ static void tpm_tis_ready(struct tpm_chip* tpm) { iowrite8(TPM_STS(tpm, tpm->locality), TPM_STS_COMMAND_READY); }
static uint8_t tpm_tis_status(struct tpm_chip* tpm) { return ioread8(TPM_STS(tpm, tpm->locality)); }
static int cr50_i2c_tis_send(struct tpm_chip *chip, uint8_t *buf, size_t len) { int status; size_t burstcnt, limit, sent = 0; uint8_t tpm_go[4] = { TPM_STS_GO }; struct stopwatch sw; stopwatch_init_msecs_expire(&sw, CR50_TIMEOUT_LONG_MS); /* Wait until TPM is ready for a command */ while (!(cr50_i2c_tis_status(chip) & TPM_STS_COMMAND_READY)) { if (stopwatch_expired(&sw)) { printk(BIOS_ERR, "%s: Command ready timeout\n", __func__); return -1; } cr50_i2c_tis_ready(chip); } while (len > 0) { uint8_t mask = TPM_STS_VALID; /* Wait for data if this is not the first chunk */ if (sent > 0) mask |= TPM_STS_DATA_EXPECT; /* Read burst count and check status */ if (cr50_i2c_wait_burststs(chip, mask, &burstcnt, &status) < 0) goto out_err; /* Use burstcnt - 1 to account for the address byte * that is inserted by cr50_i2c_write() */ limit = min(burstcnt - 1, len); if (cr50_i2c_write(chip, TPM_DATA_FIFO(chip->vendor.locality), &buf[sent], limit) != 0) { printk(BIOS_ERR, "%s: Write failed\n", __func__); goto out_err; } sent += limit; len -= limit; } /* Ensure TPM is not expecting more data */ if (cr50_i2c_wait_burststs(chip, TPM_STS_VALID, &burstcnt, &status) < 0) goto out_err; if (status & TPM_STS_DATA_EXPECT) { printk(BIOS_ERR, "%s: Data still expected\n", __func__); goto out_err; } /* Start the TPM command */ if (cr50_i2c_write(chip, TPM_STS(chip->vendor.locality), tpm_go, sizeof(tpm_go)) < 0) { printk(BIOS_ERR, "%s: Start command failed\n", __func__); goto out_err; } return sent; out_err: /* Abort current transaction if still pending */ if (cr50_i2c_tis_status(chip) & TPM_STS_COMMAND_READY) cr50_i2c_tis_ready(chip); return -1; }
/* cr50 requires all 4 bytes of status register to be written */ static void cr50_i2c_tis_ready(struct tpm_chip *chip) { uint8_t buf[4] = { TPM_STS_COMMAND_READY }; cr50_i2c_write(chip, TPM_STS(chip->vendor.locality), buf, sizeof(buf)); mdelay(CR50_TIMEOUT_SHORT_MS); }