blob: 94c8a15c98a1113903335ae28911946329ac7289 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_DEVICES_TPM_DRIVERS_TPM_REGISTERS_H_
#define SRC_DEVICES_TPM_DRIVERS_TPM_REGISTERS_H_
#include <fidl/fuchsia.hardware.tpmimpl/cpp/wire.h>
#include <lib/ddk/debug.h>
#include <lib/zx/result.h>
#include <hwreg/bitfields.h>
namespace tpm {
using fuchsia_hardware_tpmimpl::wire::RegisterAddress;
enum TpmFamily {
// TPM v1.2
kTpmFamily12 = 0,
// TPM v2.0
kTpmFamily20 = 1,
};
// This base class just implements convenience |ReadFrom| and |WriteTo| methods that use a supplied
// FIDL client to write/read a TPM register.
template <class SelfType, typename BaseType, uint16_t address>
class TpmReg : public hwreg::RegisterBase<SelfType, BaseType, hwreg::EnablePrinter> {
public:
zx_status_t ReadFrom(fidl::WireSyncClient<fuchsia_hardware_tpmimpl::TpmImpl>& client) {
auto result = client->Read(0, RegisterAddress(address), sizeof(BaseType));
if (!result.ok()) {
zxlogf(ERROR, "Failed to send read FIDL request: %s", result.FormatDescription().data());
return result.status();
}
if (result->is_error()) {
zxlogf(ERROR, "Failed to read: %d", result->error_value());
return result->error_value();
}
auto& data = result->value()->data;
if (data.count() != sizeof(BaseType)) {
zxlogf(ERROR, "Incorrect response size");
return ZX_ERR_BAD_STATE;
}
BaseType val = 0;
memcpy(&val, data.data(), sizeof(val));
this->set_reg_value(val);
return ZX_OK;
}
zx_status_t WriteTo(fidl::WireSyncClient<fuchsia_hardware_tpmimpl::TpmImpl>& client) {
auto value = this->reg_value();
auto data =
fidl::VectorView<uint8_t>::FromExternal(reinterpret_cast<uint8_t*>(&value), sizeof(value));
auto result = client->Write(0, RegisterAddress(address), data);
if (!result.ok()) {
zxlogf(ERROR, "Failed to send write FIDL request: %s", result.FormatDescription().data());
return result.status();
}
if (result->is_error()) {
zxlogf(ERROR, "Failed to write: %d", result->error_value());
return result->error_value();
}
return ZX_OK;
}
};
// All of these registers are defined in the TPM PC client platform spec.
// https://www.trustedcomputinggroup.org/wp-content/uploads/PCClientPlatform-TPM-Profile-for-TPM-2-0-v1-03-20-161114_public-review.pdf
// The PC client platform spec defines separate registers for SPI/LPC and I2C, however, the two are
// mostly compatible.
// TPM_STS: 5.5.2.5, "Status Register" and 7.3.5.6, "TPM_STS".
class StsReg : public TpmReg<StsReg, uint32_t, fidl::ToUnderlying(RegisterAddress::kTpmSts)> {
public:
DEF_ENUM_FIELD(TpmFamily, 27, 26, tpm_family);
DEF_BIT(25, reset_establishment);
DEF_BIT(24, command_cancel);
DEF_FIELD(23, 8, burst_count);
DEF_BIT(7, sts_valid);
DEF_BIT(6, command_ready);
DEF_BIT(5, tpm_go);
DEF_BIT(4, data_avail);
DEF_BIT(3, expect);
DEF_BIT(2, self_test_done);
DEF_BIT(1, response_retry);
};
// TPM_INTF_CAPABILITY: 5.5.2.7, "Interface Capability" and 7.3.5.5, "TPM_INT_CAPABILITY".
//
// Note that the I2C version of the interface only defines bits 0, 1, 2, and 7.
// Reads of other fields will always return zero.
class IntfCapabilityReg : public TpmReg<IntfCapabilityReg, uint32_t,
fidl::ToUnderlying(RegisterAddress::kTpmIntCapability)> {
public:
DEF_FIELD(30, 28, interface_version);
DEF_FIELD(10, 9, data_transfer_size_support);
DEF_BIT(8, burst_count_static);
DEF_BIT(7, command_ready_int_support);
DEF_BIT(6, interrupt_edge_falling);
DEF_BIT(5, interrupt_edge_rising);
DEF_BIT(4, interrupt_level_low);
DEF_BIT(3, interrupt_level_high);
DEF_BIT(2, locality_change_int_supported);
DEF_BIT(1, sts_valid_int_support);
DEF_BIT(0, data_avail_int_support);
};
// TPM_DID_VID: 5.4.1.1, "DID/VID Register".
class DidVidReg
: public TpmReg<DidVidReg, uint32_t, fidl::ToUnderlying(RegisterAddress::kTpmDidVid)> {
public:
DEF_FIELD(31, 16, device_id);
DEF_FIELD(15, 0, vendor_id);
};
// TPM_RID: 5.4.1.2, "RID Register".
class RevisionReg
: public TpmReg<RevisionReg, uint8_t, fidl::ToUnderlying(RegisterAddress::kTpmRid)> {
public:
DEF_FIELD(7, 0, revision_id);
};
} // namespace tpm
#endif // SRC_DEVICES_TPM_DRIVERS_TPM_REGISTERS_H_