blob: 30d1da76f8763053f0d6704e89edd7b4c64a12e0 [file] [log] [blame]
// Copyright 2017 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_MISC_DRIVERS_TPM_I2C_CR50_H_
#define SRC_DEVICES_MISC_DRIVERS_TPM_I2C_CR50_H_
#include <lib/zircon-internal/thread_annotations.h>
#include <lib/zx/handle.h>
#include <stdint.h>
#include <zircon/assert.h>
#include <zircon/types.h>
#include <memory>
#include <ddk/device.h>
#include <ddktl/protocol/i2c.h>
#include <fbl/mutex.h>
#include "tpm.h"
namespace tpm {
class I2cCr50Interface : public HardwareInterface {
public:
// Creates a new I2cCr50Interface from the given |i2c_dev|. This will issue an
// I2C transaction to determine support.
static zx_status_t Create(zx_device_t* i2c_dev, zx::handle irq,
std::unique_ptr<I2cCr50Interface>* out);
virtual ~I2cCr50Interface();
zx_status_t Validate() override;
zx_status_t ReadAccess(Locality loc, uint8_t* access) override;
zx_status_t WriteAccess(Locality loc, uint8_t access) override;
zx_status_t ReadStatus(Locality loc, uint32_t* sts) override;
zx_status_t WriteStatus(Locality loc, uint32_t sts) override;
zx_status_t ReadDidVid(uint16_t* vid, uint16_t* did) override;
zx_status_t ReadDataFifo(Locality loc, uint8_t* buf, size_t len) override;
zx_status_t WriteDataFifo(Locality loc, const uint8_t* buf, size_t len) override;
private:
template <typename T>
struct I2cRegister {
explicit constexpr I2cRegister(uint8_t addr) : addr(addr) {}
const uint8_t addr;
};
// Timeout to use if this device does not have an IRQ wired up.
static constexpr zx::duration kNoIrqTimeout = zx::msec(20);
// Delay to use between retries if an I2C operation errors.
static constexpr zx::duration kI2cRetryDelay = zx::usec(50);
I2cCr50Interface(zx_device_t* i2c_dev, zx::handle irq);
// Block until the controller signals it is ready. May return spuriously,
// so the condition being waited on should be checked after return.
zx_status_t WaitForIrqLocked() TA_REQ(lock_);
// Template for enforcing correct access size for each register read
template <typename T>
zx_status_t RegisterRead(const I2cRegister<T>& reg, T* out) {
// TODO(teisenbe): If we ever support a big-endian host, we need to do
// endianness swapping here.
static_assert(std::is_integral<T>::value, "T must be integral");
return RegisterRead(I2cRegister<uint8_t[]>(reg.addr), reinterpret_cast<uint8_t*>(out),
sizeof(T));
}
// Template for enforcing correct access size for each register write
template <typename T>
zx_status_t RegisterWrite(const I2cRegister<T>& reg, const T& val) {
static_assert(std::is_integral<T>::value, "T must be integral");
return RegisterWrite(I2cRegister<uint8_t[]>(reg.addr), reinterpret_cast<const uint8_t*>(&val),
sizeof(T));
}
// Perform an I2C read cycle
zx_status_t I2cReadLocked(uint8_t* val, size_t len) TA_REQ(lock_);
// Perform an I2C write cycle
zx_status_t I2cWriteLocked(const uint8_t* val, size_t len) TA_REQ(lock_);
// Perform a register read/write for an unsized register (indicated
// by T=uint8_t[]).
zx_status_t RegisterWrite(const I2cRegister<uint8_t[]>& reg, const uint8_t* val, size_t len)
TA_EXCL(lock_);
zx_status_t RegisterRead(const I2cRegister<uint8_t[]>& reg, uint8_t* out, size_t len)
TA_EXCL(lock_);
// Compute the register address prefix for the given locality
static constexpr uint8_t LocToPrefix(Locality loc) {
ZX_DEBUG_ASSERT(loc <= 4);
return static_cast<uint8_t>(loc << 4);
}
// These methods return an object usable with RegisterRead/RegisterWrite representing
// the specified register and locality.
static constexpr I2cRegister<uint8_t> RegisterAccess(Locality loc) {
return I2cRegister<uint8_t>(static_cast<uint8_t>(LocToPrefix(loc) | 0x0u));
}
static constexpr I2cRegister<uint32_t> RegisterStatus(Locality loc) {
ZX_DEBUG_ASSERT(loc <= 4);
return I2cRegister<uint32_t>(static_cast<uint8_t>(LocToPrefix(loc) | 0x1u));
}
static constexpr I2cRegister<uint8_t[]> RegisterDataFifo(Locality loc) {
ZX_DEBUG_ASSERT(loc <= 4);
return I2cRegister<uint8_t[]>(static_cast<uint8_t>(LocToPrefix(loc) | 0x5u));
}
static constexpr I2cRegister<uint32_t> RegisterDidVid(Locality loc) {
ZX_DEBUG_ASSERT(loc <= 4);
return I2cRegister<uint32_t>(static_cast<uint8_t>(LocToPrefix(loc) | 0x6u));
}
fbl::Mutex lock_;
// The upstream i2c device
ddk::I2cProtocolClient i2c_ TA_GUARDED(lock_);
zx::handle irq_ TA_GUARDED(lock_);
};
} // namespace tpm
#endif // SRC_DEVICES_MISC_DRIVERS_TPM_I2C_CR50_H_