1bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi//
2bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// Copyright (C) 2015 The Android Open Source Project
3bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi//
4bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// Licensed under the Apache License, Version 2.0 (the "License");
5bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// you may not use this file except in compliance with the License.
6bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// You may obtain a copy of the License at
7bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi//
8bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi//      http://www.apache.org/licenses/LICENSE-2.0
9bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi//
10bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// Unless required by applicable law or agreed to in writing, software
11bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// distributed under the License is distributed on an "AS IS" BASIS,
12bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// See the License for the specific language governing permissions and
14bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// limitations under the License.
15bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi//
16c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury
17c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury#include <algorithm>
18b21ea123afb354647305411a51d318067544606cVadim Bendebury#include <ctime>
19c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury#include <string>
2095146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury#include <unistd.h>
2195146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
2295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury#include <base/logging.h>
23c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury
24c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury#include "trunks/tpm_generated.h"
25c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury#include "trunks/trunks_ftdi_spi.h"
26c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury
2795146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury// Assorted TPM2 registers for interface type FIFO.
284dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn#define TPM_ACCESS_REG 0
294dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn#define TPM_STS_REG 0x18
306b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury#define TPM_DATA_FIFO_REG 0x24
314dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn#define TPM_DID_VID_REG 0xf00
324dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn#define TPM_RID_REG 0xf04
3395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
34c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendeburynamespace trunks {
35c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury
3695146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury// Locality management bits (in TPM_ACCESS_REG)
3795146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendeburyenum TpmAccessBits {
3895146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  tpmRegValidSts = (1 << 7),
3995146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  activeLocality = (1 << 5),
4095146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  requestUse = (1 << 1),
4195146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  tpmEstablishment = (1 << 0),
4295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury};
4395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
446b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendeburyenum TpmStsBits {
456b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury  tpmFamilyShift = 26,
466b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury  tpmFamilyMask = ((1 << 2) - 1),  // 2 bits wide
476b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury  tpmFamilyTPM2 = 1,
486b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury  resetEstablishmentBit = (1 << 25),
496b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury  commandCancel = (1 << 24),
506b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury  burstCountShift = 8,
514dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn  burstCountMask = ((1 << 16) - 1),  // 16 bits wide
526b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury  stsValid = (1 << 7),
536b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury  commandReady = (1 << 6),
546b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury  tpmGo = (1 << 5),
556b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury  dataAvail = (1 << 4),
566b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury  Expect = (1 << 3),
576b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury  selfTestDone = (1 << 2),
586b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury  responseRetry = (1 << 1),
596b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury};
606b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury
614dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn// SPI frame header for TPM transactions is 4 bytes in size, it is described
624dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn// in section "6.4.6 Spi Bit Protocol" of the TCG issued "TPM Profile (PTP)
634dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn// Specification Revision 00.43.
6495146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendeburystruct SpiFrameHeader {
6595146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  unsigned char body[4];
6695146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury};
6795146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
6895146cebd9272c71e3b3b48e12d658e57e7a328bVadim BendeburyTrunksFtdiSpi::~TrunksFtdiSpi() {
6995146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  if (mpsse_)
7095146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury    Close(mpsse_);
7195146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
7295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  mpsse_ = NULL;
7395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury}
7495146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
754dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahnbool TrunksFtdiSpi::ReadTpmSts(uint32_t* status) {
7632f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury  return FtdiReadReg(TPM_STS_REG, sizeof(*status), status);
776b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury}
786b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury
796b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendeburybool TrunksFtdiSpi::WriteTpmSts(uint32_t status) {
806b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury  return FtdiWriteReg(TPM_STS_REG, sizeof(status), &status);
816b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury}
826b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury
8395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendeburyvoid TrunksFtdiSpi::StartTransaction(bool read_write,
844dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn                                     size_t bytes,
854dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn                                     unsigned addr) {
864dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn  unsigned char* response;
8795146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  SpiFrameHeader header;
8895146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
8970e31c3379758458b4e527499ad7b2c77045add1Vadim Bendebury  usleep(10000);  // give it 10 ms. TODO(vbendeb): remove this once
9070e31c3379758458b4e527499ad7b2c77045add1Vadim Bendebury                  // cr50 SPS TPM driver performance is fixed.
9170e31c3379758458b4e527499ad7b2c77045add1Vadim Bendebury
9295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  // The first byte of the frame header encodes the transaction type (read or
9395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  // write) and size (set to lenth - 1).
9495146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  header.body[0] = (read_write ? 0x80 : 0) | 0x40 | (bytes - 1);
9595146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
9695146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  // The rest of the frame header is the internal address in the TPM
9795146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  for (int i = 0; i < 3; i++)
9895146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury    header.body[i + 1] = (addr >> (8 * (2 - i))) & 0xff;
9995146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
10095146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  Start(mpsse_);
10195146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
10295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  response = Transfer(mpsse_, header.body, sizeof(header.body));
10395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
10495146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  // The TCG TPM over SPI specification itroduces the notion of SPI flow
10595146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  // control (Section "6.4.5 Flow Control" of the TCG issued "TPM Profile
10695146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  // (PTP) Specification Revision 00.43).
10795146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
10895146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  // The slave (TPM device) expects each transaction to start with a 4 byte
10995146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  // header trasmitted by master. If the slave needs to stall the transaction,
11095146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  // it sets the MOSI bit to 0 during the last clock of the 4 byte header. In
11195146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  // this case the master is supposed to start polling the line, byte at time,
11295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  // until the last bit in the received byte (transferred during the last
11395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  // clock of the byte) is set to 1.
11495146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  while (!(response[3] & 1)) {
1154dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn    unsigned char* poll_state;
11695146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
11795146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury    poll_state = Read(mpsse_, 1);
11895146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury    response[3] = *poll_state;
11995146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury    free(poll_state);
12095146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  }
12195146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  free(response);
12295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury}
123c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury
1244dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahnbool TrunksFtdiSpi::FtdiWriteReg(unsigned reg_number,
1254dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn                                 size_t bytes,
1264dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn                                 const void* buffer) {
12795146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  if (!mpsse_)
12895146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury    return false;
12995146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
130ea14a6e1838ea01103d88cbc9ccc2eb7e57483ddVadim Bendebury  StartTransaction(false, bytes, reg_number + locality_ * 0x10000);
13195146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  Write(mpsse_, buffer, bytes);
13295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  Stop(mpsse_);
13395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  return true;
13495146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury}
13595146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
1364dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahnbool TrunksFtdiSpi::FtdiReadReg(unsigned reg_number,
1374dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn                                size_t bytes,
1384dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn                                void* buffer) {
1394dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn  unsigned char* value;
14095146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
14195146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  if (!mpsse_)
14295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury    return false;
14395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
144ea14a6e1838ea01103d88cbc9ccc2eb7e57483ddVadim Bendebury  StartTransaction(true, bytes, reg_number + locality_ * 0x10000);
14595146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  value = Read(mpsse_, bytes);
14695146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  if (buffer)
14795146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury    memcpy(buffer, value, bytes);
14895146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  free(value);
14995146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  Stop(mpsse_);
15095146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  return true;
15195146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury}
152c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury
153c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendeburysize_t TrunksFtdiSpi::GetBurstCount(void) {
154c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  uint32_t status;
155c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury
156c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  ReadTpmSts(&status);
157c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  return (size_t)((status >> burstCountShift) & burstCountMask);
158c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury}
159c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury
160c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendeburybool TrunksFtdiSpi::Init() {
1616b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury  uint32_t did_vid, status;
16295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  uint8_t cmd;
16395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
16495146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  if (mpsse_)
16595146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury    return true;
16695146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
167d3cd697fc61df7347db8c1d3589a1fee50ed90f0Vadim Bendebury  mpsse_ = MPSSE(SPI0, ONE_MHZ, MSB);
16895146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  if (!mpsse_)
16995146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury    return false;
17095146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
17195146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  // Reset the TPM using GPIOL0, issue a 100 ms long pulse.
17295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  PinLow(mpsse_, GPIOL0);
17395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  usleep(100000);
17495146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  PinHigh(mpsse_, GPIOL0);
17595146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
17695146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  FtdiReadReg(TPM_DID_VID_REG, sizeof(did_vid), &did_vid);
17795146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
17870e31c3379758458b4e527499ad7b2c77045add1Vadim Bendebury  uint16_t vid = did_vid & 0xffff;
17970e31c3379758458b4e527499ad7b2c77045add1Vadim Bendebury  if ((vid != 0x15d1) && (vid != 0x1ae0)) {
18070e31c3379758458b4e527499ad7b2c77045add1Vadim Bendebury    LOG(ERROR) << "unknown did_vid: 0x" << std::hex << did_vid;
18195146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury    return false;
18295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  }
18395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
18495146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  // Try claiming locality zero.
18595146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  FtdiReadReg(TPM_ACCESS_REG, sizeof(cmd), &cmd);
18670e31c3379758458b4e527499ad7b2c77045add1Vadim Bendebury  // tpmEstablishment can be either set or not.
18770e31c3379758458b4e527499ad7b2c77045add1Vadim Bendebury  if ((cmd & ~tpmEstablishment) != tpmRegValidSts) {
18895146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury    LOG(ERROR) << "invalid reset status: 0x" << std::hex << (unsigned)cmd;
18995146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury    return false;
19095146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  }
19195146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  cmd = requestUse;
19295146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  FtdiWriteReg(TPM_ACCESS_REG, sizeof(cmd), &cmd);
19395146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  FtdiReadReg(TPM_ACCESS_REG, sizeof(cmd), &cmd);
1944dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn  if ((cmd & ~tpmEstablishment) != (tpmRegValidSts | activeLocality)) {
19595146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury    LOG(ERROR) << "failed to claim locality, status: 0x" << std::hex
19695146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury               << (unsigned)cmd;
19795146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury    return false;
19895146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  }
19995146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
2006b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury  ReadTpmSts(&status);
2016b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury  if (((status >> tpmFamilyShift) & tpmFamilyMask) != tpmFamilyTPM2) {
2026b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury    LOG(ERROR) << "unexpected TPM family value, status: 0x" << std::hex
2036b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury               << status;
2046b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury    return false;
2056b88fbeb67f5e7a55ae880047c51056557d142a4Vadim Bendebury  }
20695146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  FtdiReadReg(TPM_RID_REG, sizeof(cmd), &cmd);
20795146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  printf("Connected to device vid:did:rid of %4.4x:%4.4x:%2.2x\n",
20895146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury         did_vid & 0xffff, did_vid >> 16, cmd);
20995146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury
21095146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  return true;
211c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury}
212c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury
213c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendeburyvoid TrunksFtdiSpi::SendCommand(const std::string& command,
214c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury                                const ResponseCallback& callback) {
21595146cebd9272c71e3b3b48e12d658e57e7a328bVadim Bendebury  printf("%s invoked\n", __func__);
216c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury}
217c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury
21832f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendeburybool TrunksFtdiSpi::WaitForStatus(uint32_t statusMask,
2194dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn                                  uint32_t statusExpected,
2204dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn                                  int timeout_ms) {
22132f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury  uint32_t status;
222b21ea123afb354647305411a51d318067544606cVadim Bendebury  time_t target_time;
223b21ea123afb354647305411a51d318067544606cVadim Bendebury
224b21ea123afb354647305411a51d318067544606cVadim Bendebury  target_time = time(NULL) + timeout_ms / 1000;
225c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  do {
226c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury    usleep(10000);  // 10 ms polling period.
227c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury    if (time(NULL) >= target_time) {
228c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury      LOG(ERROR) << "failed to get expected status " << std::hex
229c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury                 << statusExpected;
230c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury      return false;
231c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury    }
232c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury    ReadTpmSts(&status);
233c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  } while ((status & statusMask) != statusExpected);
234c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  return true;
23532f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury}
23632f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury
237c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendeburystd::string TrunksFtdiSpi::SendCommandAndWait(const std::string& command) {
23832f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury  uint32_t status;
23932f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury  uint32_t expected_status_bits;
240c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  size_t transaction_size, handled_so_far(0);
241c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury
24232f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury  std::string rv("");
24332f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury
2445ece90471dd12922f9f35ee4bf6bb6a336d4ea92Vadim Bendebury  if (!mpsse_) {
2455ece90471dd12922f9f35ee4bf6bb6a336d4ea92Vadim Bendebury    LOG(ERROR) << "attempt to use an uninitialized FTDI TPM!";
2465ece90471dd12922f9f35ee4bf6bb6a336d4ea92Vadim Bendebury    return rv;
2475ece90471dd12922f9f35ee4bf6bb6a336d4ea92Vadim Bendebury  }
2485ece90471dd12922f9f35ee4bf6bb6a336d4ea92Vadim Bendebury
24932f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury  WriteTpmSts(commandReady);
25032f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury
25132f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury  // No need to wait for the sts.Expect bit to be set, at least with the
252c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  // 15d1:001b device, let's just write the command into FIFO, not exceeding
253c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  // the minimum of the two values - burst_count and 64 (which is the protocol
254c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  // limitation)
255c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  do {
2564dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn    transaction_size = std::min(
2574dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn        std::min(command.size() - handled_so_far, GetBurstCount()), (size_t)64);
258c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury
259c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury    if (transaction_size) {
260c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury      LOG(INFO) << "will transfer " << transaction_size << " bytes";
261c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury      FtdiWriteReg(TPM_DATA_FIFO_REG, transaction_size,
262c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury                   command.c_str() + handled_so_far);
263c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury      handled_so_far += transaction_size;
264c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury    }
265c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  } while (handled_so_far != command.size());
26632f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury
26732f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury  // And tell the device it can start processing it.
26832f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury  WriteTpmSts(tpmGo);
26932f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury
27032f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury  expected_status_bits = stsValid | dataAvail;
27132f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury  if (!WaitForStatus(expected_status_bits, expected_status_bits))
2724dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn    return rv;
27332f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury
27478f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury  // The response is ready, let's read it.
27578f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury  // First we read the FIFO payload header, to see how much data to expect.
27678f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury  // The header size is fixed to six bytes, the total payload size is stored
27778f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury  // in network order in the last four bytes of the header.
27878f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury  char data_header[6];
27978f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury
28078f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury  // Let's read the header first.
28178f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury  FtdiReadReg(TPM_DATA_FIFO_REG, sizeof(data_header), data_header);
28278f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury
28378f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury  // Figure out the total payload size.
284c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  uint32_t payload_size;
28578f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury  memcpy(&payload_size, data_header + 2, sizeof(payload_size));
28678f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury  payload_size = be32toh(payload_size);
287c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  // A FIFO message with the minimum required header and contents can not be
288c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  // less than 10 bytes long. It also should never be more than 4096 bytes
289c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  // long.
290c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  if ((payload_size < 10) || (payload_size > MAX_RESPONSE_SIZE)) {
291c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury    // Something must be wrong...
292c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury    LOG(ERROR) << "Bad total payload size value: " << payload_size;
293c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury    return rv;
294c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  }
295c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury
29678f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury  LOG(INFO) << "Total payload size " << payload_size;
29778f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury
298c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  // Let's read all but the last byte in the FIFO to make sure the status
299c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  // register is showing correct flow control bits: 'more data' until the last
300c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  // byte and then 'no more data' once the last byte is read.
301c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  handled_so_far = 0;
30278f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury  payload_size = payload_size - sizeof(data_header) - 1;
303c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  // Allow room for the last byte too.
3044dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn  uint8_t* payload = new uint8_t[payload_size + 1];
305c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  do {
3064dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn    transaction_size = std::min(
3074dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn        std::min(payload_size - handled_so_far, GetBurstCount()), (size_t)64);
308c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury
309c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury    if (transaction_size) {
310c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury      FtdiReadReg(TPM_DATA_FIFO_REG, transaction_size,
311c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury                  payload + handled_so_far);
312c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury      handled_so_far += transaction_size;
313c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury    }
314c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  } while (handled_so_far != payload_size);
31578f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury
31678f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury  // Verify that there is still data to come.
31778f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury  ReadTpmSts(&status);
31878f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury  if ((status & expected_status_bits) != expected_status_bits) {
31978f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury    LOG(ERROR) << "unexpected status 0x" << std::hex << status;
32078f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury    delete[] payload;
321c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury    return rv;
32278f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury  }
32332f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury
32478f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury  // Now, read the last byte of the payload.
325c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  FtdiReadReg(TPM_DATA_FIFO_REG, sizeof(uint8_t), payload + payload_size);
32678f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury
32778f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury  // Verify that 'data available' is not asseretd any more.
32878f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury  ReadTpmSts(&status);
32978f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury  if ((status & expected_status_bits) != stsValid) {
33078f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury    LOG(ERROR) << "unexpected status 0x" << std::hex << status;
33178f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury    delete[] payload;
332c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury    return rv;
33378f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury  }
334c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury
335c60690ba852723ab55ef6eb1da99b00d4501fec0Vadim Bendebury  rv = std::string(data_header, sizeof(data_header)) +
3364dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       std::string(reinterpret_cast<char*>(payload), payload_size + 1);
33732f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury
338d3cd697fc61df7347db8c1d3589a1fee50ed90f0Vadim Bendebury  /* Move the TPM back to idle state. */
339d3cd697fc61df7347db8c1d3589a1fee50ed90f0Vadim Bendebury  WriteTpmSts(commandReady);
340d3cd697fc61df7347db8c1d3589a1fee50ed90f0Vadim Bendebury
34178f05bc20822ced174f67ce13f73e81383d3ae8cVadim Bendebury  delete[] payload;
34232f46a0b006ef7cff2a00a5223867d3064ddfff2Vadim Bendebury  return rv;
343c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury}
344c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury
345c7a43d6afb860f06e3992855d81c5bc370dcad9cVadim Bendebury}  // namespace trunks
346